我总喜欢隔一段时间就来学习学习设计模式,每当业务代码写得感觉有点累的时候就喜欢考虑一下是否可以优化一下结构,尤其是当写到重复性的代码,总想着把它复用起来,一种情况是在开发之前就设计好可复用的模块,另一种是被动的在项目当中写到重复的代码的时候再去考虑代码的重构达到良好的复用。而复用的两种方式主要是继承和组合,当然在大部分情况下,设计原则指引我们更多采用组合的方式,其实各有各的优势,继承有更明确的类之间关系,缺点就是暴露了类的实现细节,组合屏蔽了对象的细节,能够更加松散的耦合。
最近又重新温习了建造者模式和中介者模式,建造者模式呢也是一种创建型设计模式,如果一个对象很复杂,而这种复杂性更多体现在它的属性的复杂性,复杂性可以是属性本身繁琐的组装,或则是属性的组合很多,这个时候使用建造者模式是很好的一种方式,创建者能够将复杂对象的组装流程和组装的具体属性接耦开。
- 对象的组装流程
产品类Product : 假装它是一个很复杂的对象,包含很多复杂的属性,而且各个属性都有很多种组合。
导演类Director:这个导演就是负责装配流程的,它不关心各个具体的属性的创建,而是关注整个属性的装配工作。
建造类Builder: 它可以是一个接口或则是抽象类,它负责具体的产品属性的构造细节。
我们可以来写一个复杂的对象,就假设我们生产的产品是一个iphone,它定义如下:
class Iphone {
private String cpu;
private String dispaly;
// 省略setter getter toString
iphone 的处理器和显示屏可以有多种组合:
Iphone iphone = new Iphone();
iphone.setCpu("台积电");
iphone.setDispaly("三星");
System.out.println(iphone);
iphone.setCpu("三星");
iphone.setDispaly("LG");
System.out.println(iphone);
输出如下:
Iphone [cpu=台积电, dispaly=三星]
Iphone [cpu=三星, dispaly=LG]
我们的iphone是十分复杂的,如果它的属性很多,我们使用的时候每次都要去拼装属性,肯定会疯掉,苹果公司也不傻,不会把鸡蛋放在一个篮子里,所以每次搭配都会有固定的一些搭配,例如三星的处理器就不太可能再去买三星的显示器了。这些固定的搭配我们在使用的时候每次都去拼装感觉是没必要的。我们采用建造者模式来重构。
建造类:
abstract class Builder {
abstract String getCpu();
abstract String getDisplay();
}
具体的装配“套餐“:
class Builder1 extends Builder {
@Override
String getCpu() {
return "台积电";
}
@Override
String getDisplay() {
return "三星";
}
}
class Builder2 extends Builder {
@Override
String getCpu() {
return "三星";
}
@Override
String getDisplay() {
return "LG";
}
}
导演类,负责装配流程:
class Director {
private Builder builder;
public Director(Builder builder) {
super();
this.builder = builder;
}
public Iphone BuilderIphone() {
Iphone iphone = new Iphone();
// 负责装配属性
iphone.setCpu(builder.getCpu());
// 装配中途我休息会儿
System.out.println("我正在装配iphone");
iphone.setDispaly(builder.getDisplay());
return iphone;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
}
用户使用:
// 用户使用方便很多
Builder builder = new Builder1();
Director director = new Director(builder);
Iphone iphone = director.BuilderIphone();
System.out.println(iphone);
builder = new Builder2();
director.setBuilder(builder);
iphone = director.BuilderIphone();
System.out.println(iphone);
输出如下:
我正在装配iphone
Iphone [cpu=台积电, dispaly=三星]
我正在装配iphone
Iphone [cpu=三星, dispaly=LG]
我如果要新的组合方式,我只需要继承Builder再实现一个就好,不用关心组装过程,使用的时候也更加方便。
我们再来总结一下:
建造者模式解决的问题就是在于建造对象的复杂性,这和工厂模式不太一样,工厂强调的是对象的创建和对象的使用的接耦,对于对象的创建细节并没有明确的要求,建造者模式的关注点更多在于需要使用的这个对象本身的复杂性问题,各种设计模式或多或少会有类似的结构,因为它们背后的指导原则都是设计模式几大原则,因此为了满足这些原则作出一些类似的设计是很正常的,但是它们的侧重点不同的关注点,设计模式的难点也不在于理解它的设计思想,而在于理解它的使用场景,这就要求设计者理解使用场景,理解模式本身,才谈得上活用设计模式。
2020.6.10更新
新文章