设计模式之建造者模式笔记
- 说明
- Builder(生成器)
- 目录
- UML生成器(建造者)模式示例类图
- 自行车类
- 建造者抽象类
- 摩拜单车对象类
- 小黄车单车对象类
- 指挥者类
- 测试类
- 优缺点
- 模式扩展
- 手机类
- 测试类
说明
记录下学习设计模式-生成器(也叫建造者)模式的写法。
Builder(生成器)
意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构:
其中:
- Builder为创建一个Product对象的各个部件指定抽象接口。
- ConcreteBuilder实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口。
- Director构造一个使用Builder接口的对象。
- Product表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。包含定义组成组件的类,包括将这些组件装配成最终产品的接口。
适用性:
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
目录
UML生成器(建造者)模式示例类图
以该UML类图实现生成器(建造者)模式示例。
自行车类
package com.example.deesign_patterns.builder.demo1;//产品对象,自行车类
public class Bike {private String frame;//车架private String seat;//车座public String getFrame() {return frame;}public void setFrame(String frame) {this.frame = frame;}public String getSeat() {return seat;}public void setSeat(String seat) {this.seat = seat;}
}
建造者抽象类
package com.example.deesign_patterns.builder.demo1;public abstract class Builder {//声明Bike类型的变量,并进行赋值protected Bike bike=new Bike();//构造车架方法public abstract void buildFrame();//构造车座方法public abstract void buildSeat();//构造自行车的方法public abstract Bike createBike();
}
摩拜单车对象类
package com.example.deesign_patterns.builder.demo1;//具体的构建者,用来构建摩拜单车对象
public class MobileBuilder extends Builder{@Overridepublic void buildFrame() {bike.setFrame("碳纤维车架");}@Overridepublic void buildSeat() {bike.setSeat("真皮车座");}@Overridepublic Bike createBike() {return bike;}
}
小黄车单车对象类
package com.example.deesign_patterns.builder.demo1;//具体的构建者,用来构建小黄车单车对象
public class OfoBuilder extends Builder{@Overridepublic void buildFrame() {bike.setFrame("铝合金车架");}@Overridepublic void buildSeat() {bike.setSeat("橡胶车座");}@Overridepublic Bike createBike() {return bike;}
}
指挥者类
package com.example.deesign_patterns.builder.demo1;//指挥者类
public class Director {//声明builder类型的变量private Builder builder;public Director(Builder builder) {this.builder = builder;}//组装自行车的功能public Bike construct(){builder.buildFrame();builder.buildSeat();return builder.createBike();}
}
测试类
package com.example.deesign_patterns.builder.demo1;//测试类
public class Client {public static void main(String[] args) {//创建指挥者对象Director director=new Director(new MobileBuilder());//让指挥者指挥组装自行车Bike bike = director.construct();//如果正常打印出车架和车座,说明已经组装好System.out.println(bike.getFrame());System.out.println(bike.getSeat());}
}
优缺点
优点:
- 生成器(建造者)模式的封装性很好。使用生成器(建造者)模式可以有效的封装变化,在使用生成器(建造者)模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。
- 在生成器(建造者)模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 生成器(建造者)模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。
缺点:
- 生成器(建造者)模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用生成器(建造者)模式,因此其使用范围受到一定的限制。
模式扩展
生成器(建造者)模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类的构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用生成器(建造者)模式进行重构。
手机类
package com.example.deesign_patterns.builder.demo2;//手机类
public class Phone {private String cpu;//cpuprivate String screen;//屏幕private String memory;//名称private String mainBoard;//主板//私有构造方法private Phone(Builder builder) {this.cpu=builder.cpu;this.screen=builder.screen;this.memory=builder.memory;this.mainBoard=builder.mainBoard;}@Overridepublic String toString() {return "Phone{" +"cpu='" + cpu + '\'' +", screen='" + screen + '\'' +", memory='" + memory + '\'' +", mainBoard='" + mainBoard + '\'' +'}';}//静态内部类public static final class Builder{private String cpu;//cpuprivate String screen;//屏幕private String memory;//内存条private String mainBoard;//主板public Builder cpu(String cpu){this.cpu=cpu;return this;}public Builder screen(String screen){this.screen=screen;return this;}public Builder memory(String memory){this.memory=memory;return this;}public Builder mainBoard(String mainBoard){this.mainBoard=mainBoard;return this;}//使用构建者创建Phone对象public Phone build(){return new Phone(this);}}
}
测试类
package com.example.deesign_patterns.builder.demo2;//测试类
public class Client {public static void main(String[] args) {//创建手机对象,通过构建者对象获取手机对象(链式编程设置值,感觉和stream流相似)Phone phone=new Phone.Builder().cpu("intel").screen("三星屏幕").memory("金士顿内存条").mainBoard("华硕主板").build();//如果类里面有toString()方法,会自动去调用,没有写则打印对象地址System.out.println(phone);}
}