# 建造者模式

关联阅读 李兴华-生成器模式

强烈建议阅读,不然这一章直接懵逼,这里直接看出来了这个课程就是把李兴华这个简化了讲解的,李兴华这个讲得很不错,很深入,初学者真的很难看懂

定义:将一个复制对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

  • 用户只需指定需要建造的类型就可以得到他们,建造过程及细节不需要知道

类型:创建型

# 适用场景

  • 如果一个对象有非常复杂的内部结构(很多属性)
  • 想把复杂对象的创建和适用分离

# 优缺点

优点

  • 封装性好,创建和适用分离
  • 扩展性好、建造类之间独立、一定程序上解耦

缺点

  • 产生多于的 Builder 对象
  • 产品内部发生变化,建造者都要修改,成本比较大

# 建造者与工厂模式区别

建造者模式:

  • 更注重于方法的调用顺序
  • 粒度:创建复杂的产品,由各种复杂的部件组成 工厂模式:
  • 注重于创建产品
  • 粒度:创建的都是一种类型的

# coding

场景:用户找电脑城老板装电脑,实际干活的是员工

// 建造者接口
public abstract class Builder {
    public abstract Computer createComputer();

    public abstract void buildCPU(String cpu);

    public abstract void buildMainBoard(String mainBoard);

    public abstract void buildHardDisk(String hardDisk);

    public abstract void buildDisplayCard(String displayCard);

    public abstract void buildPower(String power);

    public abstract void buildMemory(String memory);
}

// 实际的建造者,可以认为是 员工
public class ActualBuilder extends Builder {
    private Computer computer = new Computer();

    @Override
    public Computer createComputer() {
        return computer;
    }

    @Override
    public void buildCPU(String cpu) {
        computer.setCPU(cpu);
    }

    @Override
    public void buildMainBoard(String mainBoard) {
        computer.setMainBoard(mainBoard);
    }

    @Override
    public void buildHardDisk(String hardDisk) {
        computer.setHardDisk(hardDisk);
    }

    @Override
    public void buildDisplayCard(String displayCard) {
        computer.setDisplayCard(displayCard);
    }

    @Override
    public void buildPower(String power) {
        computer.setPower(power);
    }

    @Override
    public void buildMemory(String memory) {
        computer.setMemory(memory);
    }
}

public class Computer {
    private String CPU;
    private String mainBoard;
    private String hardDisk;
    private String displayCard;
    private String power;
    private String memory;
    ... 省略setter...
}

// 老板
public class DirectorBoss {
    private Builder builder;

    public void setBuilder(Builder builder) {
        this.builder = builder;
    }

    public Computer createComputer(
            String cpu,
            String mainBoard,
            String hardDisk,
            String displayCard,
            String power,
            String memory
    ) {
        // 指挥员工装机,并且按照老板的装机顺序装机
        builder.buildCPU(cpu);
        builder.buildMainBoard(mainBoard);
        builder.buildHardDisk(hardDisk);
        builder.buildDisplayCard(displayCard);
        builder.buildPower(power);
        builder.buildMemory(memory);
        return builder.createComputer();
    }
}

public class Test {
    public static void main(String[] args) {
        DirectorBoss boss = new DirectorBoss();
        boss.setBuilder(new ActualBuilder());
        Computer computer = boss.createComputer(
                "酷睿I7",
                "华硕主板",
                "三星硬盘",
                "七彩虹显卡",
                "金河田电源",
                "万紫千红内存"
        );
        System.out.println(computer);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

应用层代码是不需要知道创建的逻辑的,这里看起来其实就优点繁琐了,实际的业务可能会更繁琐复杂

DirectorBoss 不是必须的,创建的工作是员工(实际创建者)创建的。对于这里的参数也是非常的多。可以使用一个流式构建,抽到创建者中去

package cn.mrcode.newstudy.design.pattern.creational.builder.v2;

/**
 * @author : zhuqiang
 * @version : V1.0
 * @date : 2018/8/30 22:27
 */
public class Computer {
    private String cpu;
    private String mainBoard;
    private String hardDisk;
    private String displayCard;
    private String power;
    private String memory;

    public Computer(ComputerBuilder computerBuilder) {
        this.cpu = computerBuilder.cpu;
        this.mainBoard = computerBuilder.mainBoard;
        this.hardDisk = computerBuilder.hardDisk;
        this.displayCard = computerBuilder.displayCard;
        this.power = computerBuilder.power;
        this.memory = computerBuilder.memory;
    }

    public static class ComputerBuilder {
        private String cpu;
        private String mainBoard;
        private String hardDisk;
        private String displayCard;
        private String power;
        private String memory;

        public Computer builder() {
            return new Computer(this);
        }

        public ComputerBuilder builderCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public ComputerBuilder builderMainBoard(String mainBoard) {
            this.mainBoard = mainBoard;
            return this;
        }

        public ComputerBuilder builderHardDisk(String hardDisk) {
            this.hardDisk = hardDisk;
            return this;
        }

        public ComputerBuilder builderDisplayCard(String displayCard) {
            this.displayCard = displayCard;
            return this;
        }

        public ComputerBuilder builderPower(String power) {
            this.power = power;
            return this;
        }

        public ComputerBuilder builderMemory(String memory) {
            this.memory = memory;
            return this;
        }
    }

    @Override
    public String toString() {
        return "Computer{" +
                "CPU='" + cpu + '\'' +
                ", mainBoard='" + mainBoard + '\'' +
                ", hardDisk='" + hardDisk + '\'' +
                ", displayCard='" + displayCard + '\'' +
                ", power='" + power + '\'' +
                ", memory='" + memory + '\'' +
                '}';
    }
}

public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer.ComputerBuilder()
                .builderCpu("酷睿I7")
                .builderDisplayCard("七彩虹显卡")
                .builder();
        System.out.println(computer);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

可以看到,通过流式构建者进行参数的选择,然后执行构建得到一个计算机

# 相关框架中的建造者模式

java.lang.StringBuilder 是 JDK 中标准的建造者模式

# guava

com.google.common.collect.ImmutableSet 不可变集合

com.google.common.collect.ImmutableSet#builder

ImmutableSet<String> build = ImmutableSet.<String>builder().add("a").add("b").build();
// [a, b]
System.out.println(build);
1
2
3
4
5

com.google.common.cache.Cache 缓存


Cache<Object, Object> cache = CacheBuilder.newBuilder()
        .initialCapacity(1000) // 初始容量
        .maximumSize(10000) // 最大容量,最近最少使用算法
        .expireAfterAccess(12, TimeUnit.HOURS) // 过期时间
        .concurrencyLevel(5) // 最大并发数,同一时间最多运行5个线程执行写入操作
        .build();
1
2
3
4
5
6
7

# spring

org.springframework.beans.factory.support.BeanDefinitionBuilder 该类中的静态方法或则实例方法基本上都是符合 建造者模式的

# mybatis

org.apache.ibatis.session.SqlSessionFactoryBuilder 该类的方法都是 build。 org.apache.ibatis.builder.xml.XMLConfigBuilder 解析 mybatis 配置文件的类 上面两个类是,建造者模式中使用建造者

org.apache.ibatis.session.SqlSessionFactoryBuilder
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
   try {
     XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
     return build(parser.parse());
  }


org.apache.ibatis.builder.xml.XMLConfigBuilder
public Configuration parse() {
  if (parsed) {
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
  }
  parsed = true;
  parseConfiguration(parser.evalNode("/configuration"));
  return configuration;
}

// 可以看到,这里按照一定的顺序进行解析,也就是建造构建
private void parseConfiguration(XNode root) {
   try {
     //issue #117 read properties first
     propertiesElement(root.evalNode("properties"));
     typeAliasesElement(root.evalNode("typeAliases"));
     pluginElement(root.evalNode("plugins"));
     objectFactoryElement(root.evalNode("objectFactory"));
     objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
     reflectionFactoryElement(root.evalNode("reflectionFactory"));
     settingsElement(root.evalNode("settings"));
     // read it after objectFactory and objectWrapperFactory issue #631
     environmentsElement(root.evalNode("environments"));
     databaseIdProviderElement(root.evalNode("databaseIdProvider"));
     typeHandlerElement(root.evalNode("typeHandlers"));
     mapperElement(root.evalNode("mappers"));
   } catch (Exception e) {
     throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
   }
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

建造者模式比较常用