开篇废话
周末因懒的原因,停更了两天。今天主要研究建造者模式。畅游各大博客网站,推荐一篇关于建造者模式的博客http://blog.csdn.net/self_study/article/details/51707029,简单明了,条例清晰。如果看不懂我写的,可以尝试去看看别人的。。。
什么是建造者模式
讲建造者模式,这里要提取几个关键词:
- 复杂对象: 这里简单的体现可以理解为,这里对象的成员数量很多,所以它很复杂。
- 构建过程: 对成员对象进行赋值,业务逻辑生成等一系列使之成为一个成熟的对象。
- 表示: 返回这个对象。
- 构建过程与表示分离: 一般来说,对成员对象的赋值通常在构造函数中,这种方式除了不够灵活之外,还有就是如果成员对象过多,因为构造函数就会显得十分臃肿。所以,我们可以将构建过程(简单的理解为赋值,这里不严谨,只是为了帮助理解概念)封装成独立的方法,然后再返回整个需要的实例对象。
那么建造者模式:就是为了解决生成复杂对象的问题,主要通过将构建过程与表示分离的方法。
如何实现建造者模式
理解了建造者模式后,我们来实现它,就相对简单了。
首先盗图一张:
建造者模式类图
可以看到,这里呈现了四个类,有时候实际开发中会将这个模型进行简化,我们这里先学习理论,因为实际操作时,灵活变动太多了,不适合讲解。但是万变不离其宗,核心思想就是这些。
- Product,都称这个为产品类,说白了就是我需要生成的类。
- Builder类,这是一个抽象类或者接口,用来规定构建对象的所需方法。
- ConcreteBuilder 对builder的抽象方法的实现类,通常对其优化为product的内部类,从而省掉builder的定义。常见的有 AlertDialog.Builder 。
- Director 调用concrete的方法的类。一般来说,使用的建造者模式时,这个也给省了。
我们先来看一个完整版的。以造汽车为例,现在我们需要一辆,有四个轮子,有四个座椅,有防风玻璃,有方向盘,发动机等等(这里只列举这几样)。
- 首先我们先看Product类,就是我们要生成的复杂对象,这里就是指小汽车。
public class Car {
List<String> tyres = new ArrayList<>();
List<String> carMounts = new ArrayList<>();
String glass;
String steeringWheel;
String engine;
public void setTyres(String tyres) {
this.tyres.add(tyres);
}
public void setCarMounts(String carMounts) {
this.carMounts.add(carMounts);
}
public void setGlass(String glass) {
this.glass = glass;
}
public void setSteeringWheel(String steeringWheel) {
this.steeringWheel = steeringWheel;
}
public void setEngine(String engine) {
this.engine = engine;
}
public List<String> getTyres() {
return tyres;
}
public List<String> getCarMounts() {
return carMounts;
}
public String getGlass() {
return glass;
}
public String getSteeringWheel() {
return steeringWheel;
}
public String getEngine() {
return engine;
}
}
这里可以看到小汽车有五个属性,然后通过setter和getter方法来对属性赋值。
- 然后我们先看Builder类,这是一个抽象类或者接口,具体使用看情况而定,我今天想用接口表示:
public interface Builder {
public void buildeTyre(int wheelNumber);
public void buildCarMounts(int carMountsNumber);
public void buildGalss();
public void buildSteeringWheel();
public void buildEngine();
public Car build();
}
这里定义了五个造小汽车零件的方法,和一个生成对象方法,因为你不能只造这些零件,还需要把这些零件给组装起来啊。
- 紧接着我们需要ConcreteBuilder类来实现这些方法啊,毕竟我们是实干家,不能光说不做!concretebuilder
public class CarBuilder implements Builder {
Car car = new Car();
@Override
public void buildeTyre(int wheelNumber) {
for (int i = 0; i < wheelNumber; i++) {
car.setTyres("已经造了" + i + "轮子了");
}
}
@Override
public void buildCarMounts(int carMountsNumber) {
for (int i = 0; i < carMountsNumber; i++) {
car.setCarMounts("已经造了" + i + "椅子了");
}
}
@Override
public void buildGalss() {
car.setGlass("防风玻璃做好了");
}
@Override
public void buildSteeringWheel() {
car.setSteeringWheel("方向盘做好了");
}
@Override
public void buildEngine() {
car.setEngine("发动机已经做好了");
}
@Override
public Car build() {
return car;
}
}
这里实现了builder接口,没什么好说的,值得注意的就是,在CarBuilder类中,维护了一个Car对象,实现的所有方法中,去调用Car的set方法,最后build()方法中去返回这个对象。
此时此刻,我们已经能通过CarBuilder类去建造我们所需要的Car对象了。但是毕竟造汽车的工序是及其复杂了,因为我们这里只简单的列举了五项,可能感觉还是比较轻松的,但是,如果有上百道工序的话,难道我们需要每次去造小车的时候都去调用这上百个方法吗。显然,这里构建的过程,我们希望是不透明的,那么我们可以将这个步骤封装起来,于是就有了Director类的出现。
- 我们希望有一个技术总工来调度负责整个造车的过程。
public class AodiDirecter {
private Builder builder;
public AodiDirecter(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildeTyre(4);
builder.buildCarMounts(4);
builder.buildEngine();
builder.buildGalss();
builder.buildSteeringWheel();
}
}
这样整个建造者模式就完成了,而我们需要一个奥迪车时,只需要:
public class Buyer {
public void buy() {
Builder builder = new CarBuilder();
AodiDirecter director = new AodiDirecter(builder);
director.construct();
Car aodiCar = builder.build();
}
}
如果说,builder是产线工人们,AodiDirecter 就可以理解为奥迪工程师,工人们只知道制造器件,工程师来统筹设计造车的工序,安排下去后,工人们按命令执行就行了。而对于买家来说,我并看不到你是怎么造的,反正我只要结果就行了。
但是这样往往会很麻烦,我们通常会对其进行精简优化。
看上面对建造者定义了四个功能模块,在实现过程中,是不是有一些,何必多此一举的感觉。这里我盗用了别人的代码,工作繁忙(太懒了)还请谅解。
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;
}
}
可以看到,整个建造者模式就是一个类,然而这个类中存在一个静态内部类Builder,这个Builder,其实对应的是建造者模式中的concreteBuilder,Computer对应的就是我们product。去掉了Builder抽象类,因为直接实现了。同时还缺少了Directer,因为这里的设计是暴露构建细节,所以就不需要了。
这种方式的好处就是,过程可控。我们来看看调用。
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();
这是一种链式调用,也是我们常见的建造者模式。我们可以对每个成员对象进行控制,从而得到我们想要的product。当然,我们看回Computer类的实现,发现,每个成员对象都是有个默认值的。也就是说,你完全可以通过new Computer.Builder().create()来获取默认的实例对象,这基本就是Directer的功能。所以精简下来,发现建造者模式还是挺实用的。
然而在大型的系统中,精简版的建造者模式,并不是很适用,因为它的针对性太强,往往呈现出来的是同一种产品,拓展性并不是很好,而我们使用原始版的话,可以对Directer进行拓展,可以更加多元灵活。
网友评论