java/android 设计模式学习笔记(10)---建造者模式
设计模式,android,java2016-06-19
  这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离。Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。一个复杂的对象有大量的组成部分,比如汽车它有车轮、方向盘、发动机、以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过程无疑会复杂,对于这种情况,为了实现在构建过程中对外部隐藏具体细节,就可以使用 Builder 模式将部件和组装过程分离,使得构建过程和部件都可以自由扩展,同时也能够将两者之间的耦合降到最低。 
  转载请注明出处:http://blog.csdn.net/self_study/article/details/51707029。  
  PS:对技术感兴趣的同鞋加群544645972一起交流。
将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。Builder 模式适用的使用场景:
  Builder 模式的 uml 类图如下所示: 
   
有四个角色:
public class Product {
    public int partB;
    public int partA;
    public int getPartA() {
        return partA;
    }
    public void setPartA(int partA) {
        this.partA = partA;
    }
    public int getPartB() {
        return partB;
    }
    public void setPartB(int partB) {
        this.partB = partB;
    }
    @Override
    public String toString() {
        return "partA : " + partA + "   partB : " + partB;
    }
}
产品类在此声明了两个 setter 方法,然后是 Builder 相关类: 
Builder.class
public abstract class Builder {
    public abstract void buildPartA(int partA);
    public abstract void buildPartB(int partB);
    public abstract Product build();
}
ConcreteBuilder.class
public class ConcreteBuilder extends Builder{
    private Product product = new Product();
    @Override
    public void buildPartA(int partA) {
        product.setPartA(partA);
    }
    @Override
    public void buildPartB(int partB) {
        product.setPartB(partB);
    }
    @Override
    public Product build() {
        return product;
    }
}
Builder 这两个类用来封装对 Product 属性的设置,最后在 build 方法中返回设置完属性的 Product 对象,最后是 Director 角色: 
Director.class
public class Director {
    private Builder builder;
    public Director(Builder builder) {
        this.builder = builder;
    }
    public void construct(int partA, int partB) {
        builder.buildPartA(partA);
        builder.buildPartB(partB);
    }
}
封装了 Builder 对象,最后是测试程序:
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct(1, 2);
Product product = builder.build();
Log.e("shawn", product.toString());
break;
运行结果
com.android.builderpattern E/shawn: partA : 1   partB : 2
代码一目了然,这里需要提到的一点是针对不同的产品可以去构建不同的 ConcreteBuilder 类,使得一个 ConcreteBuilder 类对应一个 Product 类,这点和工厂方法模式很类似,我们后面也会介绍到他们两者之间的区别。
  Builder 模式在实际开发中出现和使用的频率也是很高的,比如上面提到的 AlertDialog.Builder ,还比如非常有名的第三方开源框架 Universal-Image-Loader 库中的 ImageLoaderConfig ,他们都是使用的静态内部 Builder 类。 
  这里的 demo 也使用最简单的内部静态 Builder 类去实现,精简完之后只有 ConcreteBuilder 和 Product 角色,并且使用链式调用去实现上面提到的 fluent interface: 
Computer.class
public class Computer {
    private String CPU;
    private String GPU;
    private String memoryType;
    private int memorySize;
    private String storageType;
    private int storageSize;
    private String screenType;
    private float screenSize;
    private String OSType;
    public static class Builder {
        // Optional parameters - initialize with default values
        private String CPU = "inter-i3";
        private String GPU = "GTX-960";
        private String memoryType = "ddr3 1666MHz";
        private int memorySize = 8;//8GB
        private String storageType = "hdd";
        private int storageSize = 1024;//1TB
        private String screenType = "IPS";
        private float screenSize = 23.8f;
        private String OSType = "Windows 10";
        public Builder() {
        }
        public Builder setCPU(String CPU) {
            this.CPU = CPU;
            return this;
        }
        public Builder setGPU(String GPU) {
            this.GPU = GPU;
            return this;
        }
        public Builder setMemoryType(String memoryType) {
            this.memoryType = memoryType;
            return this;
        }
        public Builder setMemorySize(int memorySize) {
            this.memorySize = memorySize;
            return this;
        }
        public Builder setStorageType(String storageType) {
            this.storageType = storageType;
            return this;
        }
        public Builder setStorageSize(int storageSize) {
            this.storageSize = storageSize;
            return this;
        }
        public Builder setScreenType(String screenType) {
            this.screenType = screenType;
            return this;
        }
        public Builder setScreenSize(float screenSize) {
            this.screenSize = screenSize;
            return this;
        }
        public Builder setOSType(String OSType) {
            this.OSType = OSType;
            return this;
        }
        public Computer create() {
            return new Computer(this);
        }
    }
    private Computer(Builder builder) {
        CPU = builder.CPU;
        GPU = builder.GPU;
        memoryType = builder.memoryType;
        memorySize = builder.memorySize;
        storageType = builder.storageType;
        storageSize = builder.storageSize;
        screenType = builder.screenType;
        screenSize = builder.screenSize;
        OSType = builder.OSType;
    }
}
Computer 为产品类,它有一个 Builder 的静态内部类用于设置相关属性,测试代码:
Computer computer = new Computer.Builder()
        .setCPU("inter-skylake-i7")
        .setGPU("GTX-Titan")
        .setMemoryType("ddr4-2133MHz")
        .setMemorySize(16)
        .setStorageType("ssd")
        .setStorageSize(512)
        .setScreenType("IPS")
        .setScreenSize(28)
        .setOSType("Ubuntu/Window10")
        .create();
这里需要提到的关键点是关于相关属性的默认值问题:
  Builder 模式在 Android 开发中也很常用,通常作为配置类的构建器将配置的构建和表示分离开来,同时也将配置从目标类中隔离开来,避免了过多的 setter 方法。Builder 模式比较常见的实现形式是通过调用链实现,这样的方式也会使得代码更加简洁和易懂,而且同时也可以避免了目标类被过多的接口“污染”。 
  Builder 模式的优点:
Builder 模式和工厂方法模式都是属于创建型模式,他们有一些共同点:这两种设计模式的都将一个产品类对象的创建过程封装起来,让客户端从具体产品类的生成中解耦,不必了解产品类构造的细节。但是其实他们两种设计模式还是有很多不同点:
https://github.com/zhaozepeng/Design-Patterns/tree/master/BuilderPattern
http://blog.csdn.net/jason0539/article/details/44992733
https://en.wikipedia.org/wiki/Builder_pattern