美文网首页
工厂模式和建造者模式

工厂模式和建造者模式

作者: 风雪围城 | 来源:发表于2017-11-25 20:42 被阅读0次

    背景

    关于工厂模式和建造者模式,是两个意思比较相近的概念。近期在项目中抽象逻辑层的遇到了这个问题,这里整理区分一下,以便在以后能够更好的使用。
    本质上来讲,所有模式都是固定的套路,然而,总是先是熟练使用所有招数,然后才能无招胜有招吧。

    工厂模式

    顾名思义,工厂是用来生产东西的。自定义工厂,当然就是你让它生产什么,它就该生产什么。这里的什么,其实就是对象。
    这样一来,其实这种模式是用来封装对象的创建的。这是非常重要的一个目的。(我认为至少有两个目的)

    那么,为什么连创建一个对象的过程,都需要封装吗?答案是看你的使用场景和需求。
    比如说一个Bitmap的构建就可以通过工厂来实现,它有一个BitmapFactory。Bitmap可以从本地图片、输入流、数组、文件等不同数据来源构建,BitmapFactory对于生产一个Bitmap是这样处理的:

    public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)
    ...
    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts)
    ...
    public static Bitmap decodeByteArray(byte[] data, int offset, int length)
    ...
     public static Bitmap decodeResource(Resources res, int id, Options opts)
    ...
    

    当然,这样行不行呢?

    public  Bitmap(FileDescriptor fd, Rect outPadding, Options opts)
    

    即,通过一个构造函数,来实现从不同数据来源生产。这样做我觉得最大的缺点,就是逻辑上不清晰。逻辑上的清晰,在复杂的项目结构中,非常重要。和上面对比,所以,在Android中,根本无法通过构造函数创建一个Bitmap对象。
    我自己有时候,也会这么用:

    class A extends Alpha
    {}
    class B extends Alpha
    {}
    class C extends Alpha
    {}
    class SimpleFactory
    {
        public static Alpha createProduct(String type)   
        {
            if(type.equals("a"))
               return new A();
            else if(type.equals("b"))
                return new B();
            else if(type.equals("c"))
                return new C();
            else
                retrun null;
        }
    }
    

    就这么简单?
    不,有些书上,甚至不认为它是一个工厂方法。它是封装了对象没错,但是,通常所谓模式,都是一种解耦合、增强代码灵活性的方法,上面所有方法,显然并没有体现到。
    所以,这里应该还有工厂方法的第二个主要作用:体现代码的解耦能力。
    思路是这样的:对于某人(创建者)来说,当需要生产一种新的商品(产品)的时候,它才会去创建这个工厂,让这个工厂来实现生产该商品。
    现在来修改一下上面的Bitmap的构建过程,增加一点需求,即我们需要对Bitmap做一些管理。
    Now,增加一个BitmapManager,作为创建者,当它发现需要一种通过流来创建Bitmap产品的方法时,增加一条生产线(创建一个工厂)来生产它就可以了。代码上大概修改成这样:

    //BitmapFactory,抽象出来创建Bitmap的方法
    public interface SimpleBitmapFactory{
          Bitmap createBitmap();
    }
    //实际生产Bitmap的一个工厂
    public class BitmapFromStreamFactory implements SimpleBitmapFactory{
          public Bitmap createBitmap(){
              ......
          }
    }
    //Bitmap创建者
    public class BitmapManager{
      private Bitmap bitmap ;    
      public Bitmap getBitmap(SimpleBitmapFactory simplebBitmapFactory){
        Bitmap bitmap = simplebBitmapFactory.createBitmap();
        bitmap...//此处可以对bitmap做一些设置
        return bitmap ;
      }
    }
    //实际使用过程中
    bitmapManager.getBitmap(new BitmapFromStreamFactory ());
    

    这个过程和上面BitmapFactory相比主要的差别在哪里?
    这个过程更好的体现了设计模式的开闭原则(Open Close Principle)接口隔离原则,即对于软件实体(类、模块等)关闭修改,只进行扩展。同时,各个实体的依赖关系,应该是通过接口解耦,而不是依赖具体实现。
    遵循这些原则的妙用,在于当一个系统变得很复杂的时候,还能够保证代码逻辑的清晰,我们在更改需求或者功能的时候,能够减少工作量。同时,不至于发生这样的现象:我们为了需求更改了一个方法,但是该方法在另外一个隐蔽的地方也有调用,更改导致以前已经测试好的功能产生异常。
    最后,我觉得有些时候,可能不会想到什么时候该使用这种工厂方法。这,大概就要看对需求的抽象能力和判断能力了。一动一静,静的地方不需要考虑太多,关键就在于这些“动”的地方。

    建造者模式

    建造者模式也是用来构建一个对象,但是它的侧重点在于基于蓝图,或者说知识,或者说构建流程,来创建出一个新的对象。
    我们来看看OkHttp对象的构建过程,通常我们会这么使用:

    okHttpClient = new OkHttpClient.Builder()
                    .readTimeout(10, SECONDS)
                    .writeTimeout(10, SECONDS)
                    .connectTimeout(10, SECONDS)
                    .cache(cache)
                    .pingInterval(5, SECONDS)
                    .sslSocketFactory(defaultSslSocketFactory)
                    .addInterceptor(new LoggingInterceptor())
                    .build();
    

    我们build出来了一个OkHttpClient,但是构建的流程已经设置好了,如果我们需要自定义其中一部分的构建流程,在其中添加即可。这里的Builder是OkHttpClient的一个静态内部类。
    build过程实际上如下:

    OkHttpClient(Builder builder) {
        this.dispatcher = builder.dispatcher;
        this.proxy = builder.proxy;
        this.protocols = builder.protocols;
        this.connectionSpecs = builder.connectionSpecs;
        this.interceptors = Util.immutableList(builder.interceptors);
        this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
        this.eventListenerFactory = builder.eventListenerFactory;
        this.proxySelector = builder.proxySelector;
        this.cookieJar = builder.cookieJar;
        this.cache = builder.cache;
        this.internalCache = builder.internalCache;
        this.socketFactory = builder.socketFactory;
    
        boolean isTLS = false;
        for (ConnectionSpec spec : connectionSpecs) {
          isTLS = isTLS || spec.isTls();
        }
    
        if (builder.sslSocketFactory != null || !isTLS) {
          this.sslSocketFactory = builder.sslSocketFactory;
          this.certificateChainCleaner = builder.certificateChainCleaner;
        } else {
          X509TrustManager trustManager = systemDefaultTrustManager();
          this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
          this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
        }
    
        this.hostnameVerifier = builder.hostnameVerifier;
        this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
            certificateChainCleaner);
        this.proxyAuthenticator = builder.proxyAuthenticator;
        this.authenticator = builder.authenticator;
        this.connectionPool = builder.connectionPool;
        this.dns = builder.dns;
        this.followSslRedirects = builder.followSslRedirects;
        this.followRedirects = builder.followRedirects;
        this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
        this.connectTimeout = builder.connectTimeout;
        this.readTimeout = builder.readTimeout;
        this.writeTimeout = builder.writeTimeout;
        this.pingInterval = builder.pingInterval;
      }
    

    有时候,我会这么用:

    public abstract BaseClass{
      public abstract initPageParams();
      private void initMsg(){
        ...
      }
      private void initHandler(){
        ...
      }
      public BaseClass(){
        initMsg();
        initHandler();
        initParams();
      }
    }
    

    然后让具体实现类继承BaseClass。算是一种变体吧。

    总结

    好的代码,在前期,越早越好,需要充分考虑好动态和静态部分,做好抽象工作。好好运用好设计原则和设计模式,会为后来的道路减少很多不必要的麻烦。
    ok,就到这里。不到之处,还请指出。

    相关文章

      网友评论

          本文标题:工厂模式和建造者模式

          本文链接:https://www.haomeiwen.com/subject/yjuxbxtx.html