什么是建造者模式
解决了什么问题
使用场景
常见的实现场景
场景案例
使用流行的建造者模式解决问题
不适用建造者模式解决问题
使用传统的建造者模式解决问题
什么是建造者模式 隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
解决了什么问题 该模式解决的是如何将一个复杂对象(属性多)赋值的问题
使用场景 大家想想,平时如何一个对象赋值?
1、构造器
平时常用的方式,虽然构造器用起来很方便,但随着属性增多,那么需要写的构造器也会增多多,而且容易传混
2、set方式
缺点:对象状态易发生变化,也是一长串,实现起来不美观
常用的实现场景 ①lombok中的@Builder注解
比如刚才House对象
1 2 3 4 5 6 @Builder public class House { private String base; private String wall; private String cell; }
在编译后(与我们手动实现的相似)
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 public class House { private String base; private String wall; private String cell; House(String base, String wall, String cell) { this .base = base; this .wall = wall; this .cell = cell; } public static House.HouseBuilder builder () { return new House.HouseBuilder(); } public static class HouseBuilder { private String base; private String wall; private String cell; HouseBuilder() {} public House.HouseBuilder base (String base) { this .base = base; return this ; } public House.HouseBuilder wall (String wall) { this .wall = wall; return this ; } public House.HouseBuilder cell (String cell) { this .cell = cell; return this ; } public House build () { return new House(this .base, this .wall, this .cell); } } }
②StringBuilder类,相信大部分人都使用过
1 2 3 4 StringBuilder builder = new StringBuilder(); builder.append(1 ) .append(2 ) .append(3 );
源码中也是采用return this的方式实现
1 2 3 4 5 @Override public StringBuilder append (String str) { super .append(str); return this ; }
append()的方法由接口Appendable定义(该接口类似抽象建造者)
由抽象类AbstractStringBuilder实现该接口 (该抽象类 类似具体建造者,但不能实例化)
最后给StringBuilder去调用append方法 (类似指挥者/调用方)
这样的话与上方的设计模式不同了,这个就是境界,只能说写JDK源码的大佬在第五层
建造者模式,实现的方式有两种 ①流行的实现方式—链式编程
通过在对象中添加静态类的方式去创建对象
假设我需要建造一个房子,给房子的一些属性赋值
房子类
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 public class House { private String base; private String wall; private String cell; public House (Builder builder) { this .base = builder.base; this .wall = builder.wall; this .cell = builder.cell; } public static class Builder { private String base; private String wall; private String cell; public Builder base (String base) { this .base = base; return this ; } public Builder wall (String wall) { this .wall = wall; return this ; } public Builder cell (String cell) { this .cell = cell; return this ; } public House build () { return new House(this ); } } }
调用方式
1 2 3 4 5 House house = new House.Builder() .base("流行房子的地基" ) .wall("流行方式的墙" ) .cell("流行方式的顶子" ) .build();
这种方式就一个类,调用起来也美观,线程安全,强烈推荐
②传统的建造者模式 也是经典的build模式,网上一搜一大把,看着高大上,但不实用,感兴趣可以看看
如果不适用建造者模式,我们怎么进行对象赋值?
传统的建造者模式又怎么赋值?下面是代码对比
1 2 3 4 5 6 7 8 9 10 House house1 = new House(); house1.setBase("普通房子的地基" ); house1.setWall("普通房子的墙" ); house1.setCell("普通房子的吊顶" ); System.out.println(house1); Director director = new Director(); House house = director.build(new FiveBuilder()); System.out.println(house);
优势在于不论多少个属性赋值,都是一句话去创建,值在具体建造者中已设置,后面说
角色 产品,产品对象,抽象建造者,具体建造者
相当于一个对象需要4个类,而仅仅是为了解耦,没感觉到好处
UML类图
可以看到调用方(Director)确实与产品(House)进行了解耦,应该也是唯一的好处了
代码实现 房子类
1 2 3 4 5 6 7 8 9 10 public class House { private String base; private String wall; private String cell; }
抽象建造者类
1 2 3 4 5 6 7 8 9 10 public interface HouseBuilder { HouseBuilder buildBase () ; HouseBuilder buildWall () ; HouseBuilder buildCell () ; House getHouse () ; }
具体建造者
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 public class FiveBuilder implements HouseBuilder { private String base = "五角大楼的地基" ; private String wall = "五角大楼的墙" ; private String cell = "五角大楼的吊顶" ; private House house; public FiveBuilder () { house = new House(); } @Override public HouseBuilder buildBase () { house.setBase(base); return this ; } @Override public HouseBuilder buildWall () { house.setWall(wall); return this ; } @Override public HouseBuilder buildCell () { house.setCell(cell); return this ; } @Override public House getHouse () { return house; } }
指挥者/客户端(调用方)
1 2 3 4 5 6 7 8 9 public class Director { public House build (HouseBuilder builder) { builder.buildBase() .buildWall() .buildCell(); return builder.getHouse(); } }
其中的解耦思想可以借鉴,也属于面向接口编程
总结 设计模式学的终归是一种思想,不必生搬硬套,也不用死记UML类图,重要的是体会每个设计模式的思想,并通过大量的业务来累积经验,来不断证明设计模式的好处