Java设计模式之构造者模式,你真正了解过吗
Java设计模式中构造者模式的应用场景及其认识。
Kevin的博客地址:
http://lovedev.org/2017/06/02/设计模式/设计模式-Builder模式/
Builder模式可以称为建造者模式,它将一个复杂对象的构建和表示分离,同样的构建过程可以创建不同的表示
适用场景:
相同的方法,不同执行顺序,产生不同事件结果
多个部件都可以装配到一个对象中,但产生的运行结果不相同
产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
初始化一个对象时,参数过多,或者很多参数具有默认值
用 builder 模式创建共享单车为例子,示例代码:
没有贴出来的类请参考另外一篇文章
产品类:
public class Bike { private IFrame frame; private ISeat seat; private ITire tire; public IFrame getFrame() { return frame; } public void setFrame(IFrame frame) { this.frame = frame; } public ISeat getSeat() { return seat; } public void setSeat(ISeat seat) { this.seat = seat; } public ITire getTire() { return tire; } public void setTire(ITire tire) { this.tire = tire; } } |
Builder 类:
// 抽象 builder 类 public abstract class Builder { abstract void buildFrame(); abstract void buildSeat(); abstract void buildTire(); abstract Bike createBike(); } // 具体 builder 类 public class MobikeBuilder extends Builder{ private Bike mBike = new Bike(); @Override void buildFrame() { mBike.setFrame(new AlloyFrame()); } @Override void buildSeat() { mBike.setSeat(new DermisSeat()); } @Override void buildTire() { mBike.setTire(new SolidTire()); } @Override Bike createBike() { return mBike; } } public class OfoBuilder extends Builder{ private Bike mBike = new Bike(); @Override void buildFrame() { mBike.setFrame(new CarbonFrame()); } @Override void buildSeat() { mBike.setSeat(new RubberSeat()); } @Override void buildTire() { mBike.setTire(new InflateTire()); } @Override Bike createBike() { return mBike; } } |
导演类:
public class Director { private Builder mBuilder = null; public Director(Builder builder) { mBuilder = builder; } public Bike construct() { mBuilder.buildFrame(); mBuilder.buildSeat(); mBuilder.buildTire(); return mBuilder.createBike(); } } |
使用方式:
public class Click { public static void main(String[] args) { showBike(new OfoBuilder()); showBike(new MobikeBuilder()); } private void showBike(Builder builder) { Director director = new Director(builder); Bike bike = director.construct(); bike.getFrame().frame(); bike.getSeat().seat(); bike.getTire().tire(); } } |
上面示例是 Builder模式的常规用法,导演类 Director
在 Builder模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把Director和抽象建造者进行结合,示例代码:
改造后的抽象建造者:
public abstract class NewBuilder { abstract void buildFrame(); abstract void buildSeat(); abstract void buildTire(); abstract Bike createBike(); /** * 把导演类中的construct()方法合并到抽象建造者类中 * * @return 具体产品对象 */ public Bike construct() { this.buildFrame(); this.buildSeat(); this.buildTire(); return this.createBike(); } } |
这样做确实简化了系统结构,但同时也加重了抽象建造者类的职责,也不是太符合单一职责原则,如果construct()
过于复杂,建议还是封装到 Director
中
除了上面的用途外,还有另外一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用 builder模式进行重构,重构前示例代码:
// 省略 getter 和 setter 方法 public class Computer { private String cpu; private String screen; private String memory; private String mainboard; public Computer(String cpu, String screen, String memory, String mainboard) { this.cpu = cpu; this.screen = screen; this.memory = memory; this.mainboard = mainboard; } } |
重构后示例代码:
public class NewComputer { private String cpu; private String screen; private String memory; private String mainboard; public NewComputer() { throw new RuntimeException("can't init"); } private NewComputer(Builder builder) { cpu = builder.cpu; screen = builder.screen; memory = builder.memory; mainboard = builder.mainboard; } public static final class Builder { private String cpu; private String screen; private String memory; private String mainboard; public Builder() {} public Builder cpu(String val) { cpu = val; return this; } public Builder screen(String val) { screen = val; return this; } public Builder memory(String val) { memory = val; return this; } public Builder mainboard(String val) { mainboard = val; return this; } public NewComputer build() {return new NewComputer(this);} } } |
客户端:
public class Click { public static void main(String[] args) { // 非 Builder 模式 Computer computer = new Computer("cpu", "screen", "memory", "mainboard"); // Builder 模式 NewComputer newComputer = new NewComputer.Builder() .cpu("cpu") .screen("screen") .memory("memory") .mainboard("mainboard") .build(); } } |
上面的示例代码只是传入四个参数,如果参数是十四个甚至更多,builder 模式的优势将会更加明显,传递参数更加灵活,代码具有更高的可读性
建造者模式与抽象工厂模式的比较:
与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族
在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象
如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车
说了这么多 Builder模式的好处,再来看看它有什么缺点:
Builder模式所创建的产品一般具有较多共同点,组成部分也相似,所以 Builder模式不适合创建差异性很大的产品类
产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本
博客地址:
http://lovedev.org/2017/06/02/设计模式/设计模式-Builder模式/
这里学到的不仅仅是技术