java – 返回类型的静态工厂模式的有界通配符
我在Effective
Java中读到你不应该使用有界通配符作为返回类型,但我不知道我该怎么做.我的代码编译的唯一方法是使用RequestCloner<?扩展HttpUriRequest>作为静态工厂中的返回类型.我做错了什么或有解决方法吗?
注意:有一点需要注意的是HttpUriRequest有方法setHeader,但只有HttpPost有方法setEntity. abstract class RequestCloner<T extends HttpUriRequest> { protected T clonedRequest; private enum RequestType { GET,POST,DELETE } static RequestCloner<? extends HttpUriRequest> newInstance( String type,String url) { RequestType requestType = RequestType.valueOf(type); switch (requestType) { case GET: return new GetRequestCloner(url); case POST: return new PostRequestCloner(url); case DELETE: return new DeleteRequestCloner(url); default: throw new IllegalArgumentException(String.format( "Method '%s' not supported",type)); } } public abstract HttpUriRequest clone(HttpServletRequest servletRequest) throws IOException; protected void cloneHeaders(HttpServletRequest servletRequest) { @SuppressWarnings("unchecked") Enumeration<String> e = servletRequest.getHeaderNames(); while (e.hasMoreElements()) { String header = e.nextElement(); if (!header.equalsIgnoreCase("Content-Length") && !header.equalsIgnoreCase("Authorization") && !header.equalsIgnoreCase("Host")) { clonedRequest.setHeader(new BasicHeader(header,servletRequest.getHeader(header))); } } } } ... class GetRequestCloner extends RequestCloner<HttpGet> { GetRequestCloner(String url) { this.clonedRequest = new HttpGet(url); } @Override public HttpUriRequest clone(HttpServletRequest servletRequest) { cloneHeaders(servletRequest); return clonedRequest; } } ... class PostRequestCloner extends RequestCloner<HttpPost> { private static final int MAX_STR_LEN = 1024; PostRequestCloner(String url) { this.clonedRequest = new HttpPost(url); } @Override public HttpUriRequest clone(HttpServletRequest servletRequest) throws IOException { cloneHeaders(servletRequest); cloneBody(servletRequest); return clonedRequest; } private void cloneBody(HttpServletRequest servletRequest) throws IOException { StringBuilder sb = new StringBuilder(""); BufferedReader br = new BufferedReader(new InputStreamReader( servletRequest.getInputStream(),"UTF-8")); String line = ""; while ((line = br.readLine()) != null && sb.length() < MAX_STR_LEN) { sb.append(line); } br.close(); clonedRequest.setEntity(new StringEntity(sb.toString(),"UTF-8")); } } ... class DeleteRequestCloner extends RequestCloner<HttpDelete> { DeleteRequestCloner(String url) { this.clonedRequest = new HttpDelete(url); } @Override public HttpUriRequest clone(HttpServletRequest servletRequest) { cloneHeaders(servletRequest); return clonedRequest; } } 解决方法
查看您的代码,您的类不需要是通用的.进一步看,存在一个奇怪的问题,即调用者在URL中传递以创建克隆者,然后将HttpServletRequest(理论上可以是不同类型的请求)传递到克隆方法中.
我可以看到两种解决方案,具体取决于您是否真的需要RequestCloner是通用的. 如果RequestCloner不需要通用 更改基类如下: abstract class RequestCloner { private enum RequestType { GET,DELETE } public static HttpUriRequest cloneRequest(HttpServletRequest servletRequest) throws IOException { RequestCloner cloner = createCloner(servletRequest); String uri = servletRequest.getRequestURI(); return cloner.clone(uri,servletRequest); } private static RequestCloner createCloner(HttpServletRequest servletRequest) { RequestType requestType = RequestType.valueOf(servletRequest. getMethod()); switch (requestType) { case GET: return new GetRequestCloner(); case POST: return new PostRequestCloner(); case DELETE: return new DeleteRequestCloner(); default: throw new AssertionFailedError(String.format( "RequestType '%s' not supported",requestType)); } } protected abstract HttpUriRequest clone( String uri,HttpServletRequest servletRequest) throws IOException; protected final void cloneHeaders( HttpServletRequest servletRequest,HttpUriRequest clonedRequest) { // note addition of parameter // same code as before,but modify the passed-in clonedRequest } } RequestCloner的子类将覆盖clone(),可选地更改返回值以返回HttpUriRequest的子类: class PostRequestCloner extends RequestCloner { private static final int MAX_STR_LEN = 1024; @Override protected HttpPost clone( String uri,HttpServletRequest servletRequest) throws IOException { HttpPost clonedRequest = new HttpPost(uri); cloneHeaders(servletRequest,clonedRequest); cloneBody(servletRequest,clonedRequest); return clonedRequest; } ... } 上述解决方案的缺点是cloneRequest()的返回值与作为POST请求的GET请求相同. 如果您愿意,可以通过向枚举添加代码来删除开关: abstract class RequestCloner { private enum RequestType { GET(new GetRequestCloner()),POST(new PostRequestCloner()),DELETE(new DeleteRequestCLoner()); private final RequestCloner requestCloner; private RequestType(RequestCloner requestCloner) { this.requestCloner = requestCloner(); } } public static HttpUriRequest cloneRequest(HttpServletRequest servletRequest) throws IOException { RequestType requestType = RequestType.valueOf(servletRequest. getMethod()); String uri = servletRequest.getRequestURI(); return requestType.requestCloner.clone(uri,servletRequest); } ... } 如果希望返回值依赖于请求的类型,则调用者需要指定某种类型的标记,显式引用RequestCloner的子类,或者为每种类型的请求向RequestCloner添加一个静态方法. 如果RequestCloner需要通用 鉴于问题中的代码,使RequestCloner通用的唯一好处是使clone()的返回值与GET或POST不同. 为此,您有两种选择 >使子类(及其构造函数)公开. 以下是选项2的示例: public static RequestCloner<HttpPost> forPostRequest(String URL) { return new PostRequestCloner(URL); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |