干了很多年的程序员了,我今天终于要实现人生梦想的第一步,a dream car 保时捷卡宴。我兴冲冲的跑到保时捷4S店,来到这里,不禁为4S店的豪华装修感到震撼,也为这里的每一辆车感到惊艳~这时售车小姐姐拿起车辆配置单,我就刷刷刷的选了好几种配置的车型,最终确定了某个配置。处于好奇就问了妹子造车的过程:
public static class CayenneZhuMengBan {
public void engine() {
System.out.println("组装发动机:3.0T V6");
}
public void cruise() {
System.out.println("刷入巡航系统:定速巡航");
}
public void sound() {
System.out.println("组装音响:BOSS");
}
public void build() {
System.out.println("建造卡宴逐梦版");
}
}
public static class CayenneCoupeGT {
public void engine() {
System.out.println("组装发动机:4.0T V8");
}
public void cruise() {
System.out.println("刷入巡航系统:全速自适应巡航");
}
public void sound() {
System.out.println("组装音响:柏林之声");
}
public void build() {
System.out.println("建造卡宴CoupeGT版");
}
}
客户端代码:
public static void main(String[] args) {
CayenneZhuMengBan zhuMengBan = new CayenneZhuMengBan();
zhuMengBan.engine();
zhuMengBan.sound();
zhuMengBan.cruise();
zhuMengBan.build();
CayenneCoupeGT coupeGT = new CayenneCoupeGT();
coupeGT.engine();
coupeGT.sound();
coupeGT.cruise();
coupeGT.build();
}
身为程序员的我一眼发现问题所在。卡宴车型那么多,而且还有选配。
问题一:如果为每一种配置或配置组合都写一个类,那么不就是类爆炸了吗?不符合开闭原则。那我用工厂模式不就行了吗?不太准确,工厂模式侧重生产产品,保时捷工厂只生产保时捷汽车(车型,如卡宴,paramecia等),不应负责具体装车细节。这里提一下,如果工厂模式既生产车型,又负责组装车,那么他就不符合设计模式的“单一原则”。单一原则强调,每个类,接口,功能模块等都应该只有一种职责。过多的职责会带来,代码臃肿,责任不明确,解耦困难。就像我们工作一样,让你即写代码又去做产品经理,项目经理,能干好不??
问题二:造车的过程都是有顺序,肯定需要先安装发动机(假如),才能再安装音响呀,巡航系统呀,如果负责装配零件的工人搞错了顺序,那不就完蛋了?!
问题三:应该给卡宴汽车一个抽象,不应该具体化为逐梦版,CoupeGT版等,后期想新增配置车型会非常困难,不易于维护,其实还是不符合开闭原则
我把造成的车问题反馈给了保时捷,保时捷设计师傅说“你的方案真不错,我们优化一下”
建立抽象建造者类:
public interface Builder {
void engine();
void sound();
void cruise();
CayenneCar build();
}
建立保时捷卡宴车类(产品):
public class CayenneCar {
private String model;
private String engine;
private String sound;
private String cruise;
public CayenneCar(String model) {
this.model = model;
}
@Override
public String toString() {
return "CayenneCar{" +
"model='" + model + '\'' +
", engine='" + engine + '\'' +
", sound='" + sound + '\'' +
", cruise='" + cruise + '\'' +
'}';
}
}
建立抽象建造者的实现类,逐梦版与CoupeGT版类:
public class ZhuMengBanBuilder implements Builder {
private CayenneCar cayenneCar = new CayenneCar("卡宴逐梦版");
public void engine() {
System.out.println("组装发动机:3.0T V6");
cayenneCar.engine = "3.0T V6";
}
public void cruise() {
System.out.println("刷入巡航系统:定速巡航");
cayenneCar.cruise = "定速巡航";
}
public void sound() {
System.out.println("组装音响:BOSS");
cayenneCar.sound = "BOSS";
}
public CayenneCar build() {
return cayenneCar;
}
}
public class CoupeGTBuilder implements Builder {
private CayenneCar cayenneCar = new CayenneCar("卡宴逐梦版");
public void engine() {
System.out.println("组装发动机:4.0T V8");
cayenneCar.engine = "4.0T V8";
}
public void cruise() {
System.out.println("刷入巡航系统:全速自适应巡航");
cayenneCar.cruise = "全速自适应巡航";
}
public void sound() {
System.out.println("组装音响:柏林之声");
cayenneCar.sound = "柏林之声";
}
public CayenneCar build() {
return cayenneCar;
}
}
建立指挥者类(保时捷装配工):
public class PorscheAssembler{
public void assemble(Builder builder) {
builder.engine();
builder.sound();
builder.cruise();
}
}
客户端代码:
public static void main(String[] args) {
Builder zhuMengBanBuilder = new ZhuMengBanBuilder();
Builder coupeGTBuilder = new CoupeGTBuilder();
PorscheAssembler assembler = new PorscheAssembler();
assembler.assemble(zhuMengBanBuilder);
CayenneCar zhuMengCar = zhuMengBanBuilder.build();
System.out.println(zhuMengCar);
assembler.assemble(coupeGTBuilder);
CayenneCar coupeGT = coupeGTBuilder.build();
System.out.println(coupeGT);
}
总结:
经过建造者模式装配的卡宴汽车,仅需根据不同的配置建立不同的Builder类,就可以构造出不同的卡宴车型,符合开闭原则。它隐藏了建造产品的复杂细节,使产品构造与产品本身解耦。由于建造者只负责建造,所以符合单一原则。这里再提一个,里氏替换原则,这个原则是开闭原则的一个实现,即子类一定可以替换父类,其实就是说的面向对象的继承。在我们保时捷的代码中,CoupeGTBuilder类一定可以替换成Builder类,即CoupeGTBuilder coupeGTBuilder = new CoupeGTBuilder();
我们的代码中其实也有些地方需要改进,产品类CayenneCar类我们应该把它改成接口,不应该限制为专有车型卡宴,因为无论哪种车型,装配的动作基本上都是一致的,就像每个车型都有装配发动机,装配轮胎等等,即使有不同车型有不同的地方,我们可以在里面用桥接模式或者其他复合模式(各种模式的组合)。如果产品的构造不复杂,且无顺序要求,那就没有必要用指挥者类了,可以把构造的过程直接写在Builder类的build方法中。还有一点,Builder类接口中定义的方法,也可以带上参数,客户端负责动态传入。
最后给出GOF的官方定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2427






