工厂模式和建造者模式

背景

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

工厂模式

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

那么,为什么连创建一个对象的过程,都需要封装吗?答案是看你的使用场景和需求。
比如说一个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,就到这里。不到之处,还请指出。

你可能感兴趣的:(工厂模式和建造者模式)