zoukankan      html  css  js  c++  java
  • 设计模式复习--简单工厂模式

       模式场景:在一个披萨店中,要根据不同客户的口味,生产不同的披萨,如素食披萨、希腊披萨等披萨。

            该例的UML结构图如下:

     Pizza制造工厂:SimplyPizzaFactory.java

    /**
     * 专门用于创建披萨的工厂类
     */
    public class SimplePizzaFactory {
            public Pizza createPizza(String type){
                    Pizza pizza = null;
                    
                    if(type.equals("cheese")){
                            pizza = new CheesePizza();
                    }
                    else if(type.equals("clam")){
                            pizza = new ClamPizza();
                    }
                    else if(type.equals("pepperoni")){
                            pizza = new PepperoniPizza();
                    }
                    else if(type.equals("veggie")){
                            pizza = new VeggiePizze();
                    }
                    
                    return pizza;
            }
    }

    其中CheesePizza,ClamPizza,PepperoniPizza,VeggiePizze是集成自Pizza的子类

    Pizza.java

    /**
     * 抽象pizza类
     */
    public abstract class Pizza {
            public abstract void prepare();
            
            public abstract void bake();
            
            public abstract void cut();
            
            public abstract void box();
    }

    CheesePizza.java

    public class CheesePizza extends Pizza{
    
            @Override
            public void bake() {
                    System.out.println("bake CheesePizza ...");
            }
    
            @Override
            public void box() {
                    System.out.println("box CheesePizza ...");
            }
    
            @Override
            public void cut() {
                    System.out.println("cut CheesePizza ...");
            }
    
            @Override
            public void prepare() {
                    System.out.println("prepare CheesePizza ...");
            }
    }

    PizzaStore.java

    public class PizzaStore {
            SimplePizzaFactory factory;      //SimplePizzaFactory的引用
            public PizzaStore(SimplePizzaFactory factory){
                    this.factory = factory;
            }
            
            public Pizza orderPizza(String type){
                Pizza pizza;
                pizza = factory.createPizza(type);     //使用工厂对象的创建方法,而不是直接new。这里不再使用具体实例化
                    
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
                    
                return pizza;
            }
    }

    优缺点 

         优点

                1、简单工厂模式实现了对责任的分割,提供了专门的工厂类用于创建对象。

                2、客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。

                3、通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

     

             缺点

                1、由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。

                2、使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。

                3、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

                4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

        5、 简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,但是如果产品过多时,会导致工厂代码非常复杂。

    android源码里面使用工厂设计模式的地方:

    BitMapFactory,还有就是Volley里面对HttpStack的实例化代码:

    HttpStack为网络模块的接口;

    public interface HttpStack {
        /**
         * Performs an HTTP request with the given parameters.
         *
         * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
         * and the Content-Type header is set to request.getPostBodyContentType().</p>
         *
         * @param request the request to perform
         * @param additionalHeaders additional headers to be sent together with
         *         {@link Request#getHeaders()}
         * @return the HTTP response
         */
        public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError;
    
    }

    HurlStack为实现httpStack的类,用httpUrlConnection来实现网络操作;

    public class HurlStack implements HttpStack {
    
        private static final String HEADER_CONTENT_TYPE = "Content-Type";
    
        /**
         * An interface for transforming URLs before use.
         */
        public interface UrlRewriter {
            /**
             * Returns a URL to use instead of the provided one, or null to indicate
             * this URL should not be used at all.
             */
            public String rewriteUrl(String originalUrl);
        }
    
        private final UrlRewriter mUrlRewriter;
        private final SSLSocketFactory mSslSocketFactory;
    
        public HurlStack() {
            this(null);
        }
    
        /**
         * @param urlRewriter Rewriter to use for request URLs
         */
        public HurlStack(UrlRewriter urlRewriter) {
            this(urlRewriter, null);
        }
    
        /**
         * @param urlRewriter Rewriter to use for request URLs
         * @param sslSocketFactory SSL factory to use for HTTPS connections
         */
        public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
            mUrlRewriter = urlRewriter;
            mSslSocketFactory = sslSocketFactory;
        }
    
        @Override
        public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
                throws IOException, AuthFailureError {
            String url = request.getUrl();
            HashMap<String, String> map = new HashMap<String, String>();
            map.putAll(request.getHeaders());
            map.putAll(additionalHeaders);
            if (mUrlRewriter != null) {
                String rewritten = mUrlRewriter.rewriteUrl(url);
                if (rewritten == null) {
                    throw new IOException("URL blocked by rewriter: " + url);
                }
                url = rewritten;
            }
            URL parsedUrl = new URL(url);
            HttpURLConnection connection = openConnection(parsedUrl, request);
            for (String headerName : map.keySet()) {
                connection.addRequestProperty(headerName, map.get(headerName));
            }
            setConnectionParametersForRequest(connection, request);
            // Initialize HttpResponse with data from the HttpURLConnection.
            ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
            int responseCode = connection.getResponseCode();
            if (responseCode == -1) {
                // -1 is returned by getResponseCode() if the response code could not be retrieved.
                // Signal to the caller that something was wrong with the connection.
                throw new IOException("Could not retrieve response code from HttpUrlConnection.");
            }
            StatusLine responseStatus = new BasicStatusLine(protocolVersion,
                    connection.getResponseCode(), connection.getResponseMessage());
            BasicHttpResponse response = new BasicHttpResponse(responseStatus);
            response.setEntity(entityFromConnection(connection));
            for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
                if (header.getKey() != null) {
                    Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
                    response.addHeader(h);
                }
            }
            return response;
        }
    
        /**
         * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
         * @param connection
         * @return an HttpEntity populated with data from <code>connection</code>.
         */
        private static HttpEntity entityFromConnection(HttpURLConnection connection) {
            BasicHttpEntity entity = new BasicHttpEntity();
            InputStream inputStream;
            try {
                inputStream = connection.getInputStream();
            } catch (IOException ioe) {
                inputStream = connection.getErrorStream();
            }
            entity.setContent(inputStream);
            entity.setContentLength(connection.getContentLength());
            entity.setContentEncoding(connection.getContentEncoding());
            entity.setContentType(connection.getContentType());
            return entity;
        }
    
        /**
         * Create an {@link HttpURLConnection} for the specified {@code url}.
         */
        protected HttpURLConnection createConnection(URL url) throws IOException {
            return (HttpURLConnection) url.openConnection();
        }
    
        /**
         * Opens an {@link HttpURLConnection} with parameters.
         * @param url
         * @return an open connection
         * @throws IOException
         */
        private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
            HttpURLConnection connection = createConnection(url);
    
            int timeoutMs = request.getTimeoutMs();
            connection.setConnectTimeout(timeoutMs);
            connection.setReadTimeout(timeoutMs);
            connection.setUseCaches(false);
            connection.setDoInput(true);
    
            // use caller-provided custom SslSocketFactory, if any, for HTTPS
            if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
                ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
            }
    
            return connection;
        }
    
        @SuppressWarnings("deprecation")
        /* package */ static void setConnectionParametersForRequest(HttpURLConnection connection,
                Request<?> request) throws IOException, AuthFailureError {
            switch (request.getMethod()) {
                case Method.DEPRECATED_GET_OR_POST:
                    // This is the deprecated way that needs to be handled for backwards compatibility.
                    // If the request's post body is null, then the assumption is that the request is
                    // GET.  Otherwise, it is assumed that the request is a POST.
                    byte[] postBody = request.getPostBody();
                    if (postBody != null) {
                        // Prepare output. There is no need to set Content-Length explicitly,
                        // since this is handled by HttpURLConnection using the size of the prepared
                        // output stream.
                        connection.setDoOutput(true);
                        connection.setRequestMethod("POST");
                        connection.addRequestProperty(HEADER_CONTENT_TYPE,
                                request.getPostBodyContentType());
                        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                        out.write(postBody);
                        out.close();
                    }
                    break;
                case Method.GET:
                    // Not necessary to set the request method because connection defaults to GET but
                    // being explicit here.
                    connection.setRequestMethod("GET");
                    break;
                case Method.DELETE:
                    connection.setRequestMethod("DELETE");
                    break;
                case Method.POST:
                    connection.setRequestMethod("POST");
                    addBodyIfExists(connection, request);
                    break;
                case Method.PUT:
                    connection.setRequestMethod("PUT");
                    addBodyIfExists(connection, request);
                    break;
                case Method.HEAD:
                    connection.setRequestMethod("HEAD");
                    break;
                case Method.OPTIONS:
                    connection.setRequestMethod("OPTIONS");
                    break;
                case Method.TRACE:
                    connection.setRequestMethod("TRACE");
                    break;
                case Method.PATCH:
                    connection.setRequestMethod("PATCH");
                    addBodyIfExists(connection, request);
                    break;
                default:
                    throw new IllegalStateException("Unknown method type.");
            }
        }
    
        private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)
                throws IOException, AuthFailureError {
            byte[] body = request.getBody();
            if (body != null) {
                connection.setDoOutput(true);
                connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());
                DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                out.write(body);
                out.close();
            }
        }
    }

    HttpClientStack也是实现HttpStack的类,用HttpClient来实现网络操作;

    public class HttpClientStack implements HttpStack {
        protected final HttpClient mClient;
    
        private final static String HEADER_CONTENT_TYPE = "Content-Type";
    
        public HttpClientStack(HttpClient client) {
            mClient = client;
        }
    
        private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
            for (String key : headers.keySet()) {
                httpRequest.setHeader(key, headers.get(key));
            }
        }
    
        @SuppressWarnings("unused")
        private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) {
            List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size());
            for (String key : postParams.keySet()) {
                result.add(new BasicNameValuePair(key, postParams.get(key)));
            }
            return result;
        }
    
        @Override
        public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
                throws IOException, AuthFailureError {
            HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
            addHeaders(httpRequest, additionalHeaders);
            addHeaders(httpRequest, request.getHeaders());
            onPrepareRequest(httpRequest);
            HttpParams httpParams = httpRequest.getParams();
            int timeoutMs = request.getTimeoutMs();
            // TODO: Reevaluate this connection timeout based on more wide-scale
            // data collection and possibly different for wifi vs. 3G.
            HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
            HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
            return mClient.execute(httpRequest);
        }
    
        /**
         * Creates the appropriate subclass of HttpUriRequest for passed in request.
         */
        @SuppressWarnings("deprecation")
        /* protected */ static HttpUriRequest createHttpRequest(Request<?> request,
                Map<String, String> additionalHeaders) throws AuthFailureError {
            switch (request.getMethod()) {
                case Method.DEPRECATED_GET_OR_POST: {
                    // This is the deprecated way that needs to be handled for backwards compatibility.
                    // If the request's post body is null, then the assumption is that the request is
                    // GET.  Otherwise, it is assumed that the request is a POST.
                    byte[] postBody = request.getPostBody();
                    if (postBody != null) {
                        HttpPost postRequest = new HttpPost(request.getUrl());
                        postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());
                        HttpEntity entity;
                        entity = new ByteArrayEntity(postBody);
                        postRequest.setEntity(entity);
                        return postRequest;
                    } else {
                        return new HttpGet(request.getUrl());
                    }
                }
                case Method.GET:
                    return new HttpGet(request.getUrl());
                case Method.DELETE:
                    return new HttpDelete(request.getUrl());
                case Method.POST: {
                    HttpPost postRequest = new HttpPost(request.getUrl());
                    postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
                    setEntityIfNonEmptyBody(postRequest, request);
                    return postRequest;
                }
                case Method.PUT: {
                    HttpPut putRequest = new HttpPut(request.getUrl());
                    putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
                    setEntityIfNonEmptyBody(putRequest, request);
                    return putRequest;
                }
                case Method.HEAD:
                    return new HttpHead(request.getUrl());
                case Method.OPTIONS:
                    return new HttpOptions(request.getUrl());
                case Method.TRACE:
                    return new HttpTrace(request.getUrl());
                case Method.PATCH: {
                    HttpPatch patchRequest = new HttpPatch(request.getUrl());
                    patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
                    setEntityIfNonEmptyBody(patchRequest, request);
                    return patchRequest;
                }
                default:
                    throw new IllegalStateException("Unknown request method.");
            }
        }
    
        private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,
                Request<?> request) throws AuthFailureError {
            byte[] body = request.getBody();
            if (body != null) {
                HttpEntity entity = new ByteArrayEntity(body);
                httpRequest.setEntity(entity);
            }
        }
    
        /**
         * Called before the request is executed using the underlying HttpClient.
         *
         * <p>Overwrite in subclasses to augment the request.</p>
         */
        protected void onPrepareRequest(HttpUriRequest request) throws IOException {
            // Nothing.
        }
    
        /**
         * The HttpPatch class does not exist in the Android framework, so this has been defined here.
         */
        public static final class HttpPatch extends HttpEntityEnclosingRequestBase {
    
            public final static String METHOD_NAME = "PATCH";
    
            public HttpPatch() {
                super();
            }
    
            public HttpPatch(final URI uri) {
                super();
                setURI(uri);
            }
    
            /**
             * @throws IllegalArgumentException if the uri is invalid.
             */
            public HttpPatch(final String uri) {
                super();
                setURI(URI.create(uri));
            }
    
            @Override
            public String getMethod() {
                return METHOD_NAME;
            }
    
        }
    }

    两个都是为了实现HttpStack里面的performRequest方法;

    然后在Volley的类中newRequestQueue里面根据不同的android 的版本号,选择使用HttpUrlConnection的HurlStack或者使用HttpClientStack的HurlStack;

        /**
         * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
         *获取Volley对象
         * @param context A {@link Context} to use for creating the cache dir.
         * @param stack An {@link HttpStack} to use for the network, or null for default.
         * @return A started {@link RequestQueue} instance.
         */
        @SuppressLint("NewApi")
        public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
            File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
    
            String userAgent = "volley/0";
            try {
                String packageName = context.getPackageName();
                PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
                userAgent = packageName + "/" + info.versionCode;
            } catch (NameNotFoundException e) {
            }
    
            if (stack == null) {
                if (Build.VERSION.SDK_INT >= 9) {
                    stack = new HurlStack();
                } else {
                    // Prior to Gingerbread, HttpUrlConnection was unreliable.
                    // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                    stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
                }
            }
    
            Network network = new BasicNetwork(stack);
    
            RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
            queue.start();
    
            return queue;
            /*
             * 实例化一个RequestQueue,其中start()主要完成相关工作线程的开启,
             * 比如开启缓存线程CacheDispatcher先完成缓存文件的扫描, 还包括开启多个NetworkDispatcher访问网络线程,
             * 该多个网络线程将从 同一个 网络阻塞队列中读取消息
             * 
             * 此处可见,start()已经开启,所有我们不用手动的去调用该方法,在start()方法中如果存在工作线程应该首先终止,并重新实例化工作线程并开启
             * 在访问网络很频繁,而又重复调用start(),势必会导致性能的消耗;但是如果在访问网络很少时,调用stop()方法,停止多个线程,然后调用start(),反而又可以提高性能,具体可折中选择
             */
        }

    2015年12月8日20:37:57更新

    android中工厂设计模式的使用:

    比如一个业务数据的来源有三种,分别是数据库,xml文件,文件,我们就可以按照如下方式来实现:

    1,创建一个基类抽象类,抽象对数据库,xml,文件的增删改查的方法。

    2,继承抽象基类,并实现基类的抽象方法(数据库实现类,xml实现类,文件实现类)。

    3,然后就是创建如下的简单工厂类来实现:

    // 抽象的工厂类,定义了其子类必须实现的createProduct()方法 
      abstract class Factory { 
        //运用了Java 中的泛型和反射技术 
        public abstract <T extends IOHandler> T createProduct(Class<T> c); 
      } 
        
      class ConcreteFactory extends Factory { 
        public <T extends IOHandler> T createProduct(Class<T> c) { 
          T handler = null; 
          try { 
            handler = (T) Class.forName(c.getName()).newInstance(); 
          } catch (Exception e) { 
            e.printStackTrace(); 
          } 
          return handler; 
        } 
      } 

    使用数据库,就传进去数据库的class,调用数据库相关操作;

    使用xml,传进去xml的class,调用xml的相关操作;

    使用文件,闯进去文件操作的class,调用使用文件的相关操作。

    使用简单工厂的缺点就是每次我们写新得产品的时候,总是创建一个新类,引入抽象类,到时类数量增加。

  • 相关阅读:
    (数字类型,进制转换,字符串,列表)介绍,操作,内置方法
    谁说JavaScript容易?
    sass/scss 和 less的区别
    为什么commonjs不适合于浏览器端
    nodejs与v8引擎
    单例模式和angular的services的使用方法
    深入浅出 妙用Javascript中apply、call、bind
    单页Web应用优缺点
    JavaScript面向对象
    使用iframe的优缺点,为什么少用iframe以及iframe和frame的区别。
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/3679287.html
Copyright © 2011-2022 走看看