从需求出发,理一下建造者模式可以解决怎样的问题。
刚开始看建造者的时候,有“指挥者”,“建造者”这样的概念。虽然看懂实例比较容易,但是也一直不清楚为什么要这么做。所以这里打算举一个例子,慢慢体会一下有无这些“角色”时,对我们的程序会带来怎样的影响。
建造者模式用来解决复杂对象的获取的问题,那么我们就先来一个复杂的对象:S。S这个对象,是由3个其他对象——A,B,C组合而成的。如果按常规的方式,我们是这样获得对象的:
因为S对象里面的A,B,C也需要有值,所以我们还得挨个给他们去赋值。最后的输出语句,就相当于我们在使用对象s了。可以看到,主函数一共5条语句,前4条都是在构建对象,只有最后一句是在使用。而建造者模式,就是想让这一复杂的创建过程被独立出来,实现模块的分离。不然只要用到s对象,就要经历如此复杂的过程,想必是无法接受的。
下面就来创建一个类"SBuilder",来专门做创建对象这件事。(为了看着简洁一点,这里就都不做访问权限的声明了。)
有了这个类,我们想要获得s,只需要:
public static void main(String[] args) {
S s = new SBuilder01().getS();
System.out.println(s.toString());
}
可以看出,一条语句就可以创建出有内容的s对象,并且不用关心创建的细节。
虽然现在SBuilder里的getS()方法,逻辑还是很简单的,但如果ABC对象还需要传参,从而得到不同属性的s对象,那么一个建造者可能就不够用了。所以还会需要SBuilder02,SBuilder03,SBuilder04等等。
面对这种情况,User获得s的过程就变成了这样:
public static void main(String[] args) {
S s1 = new SBuilder01().getS();
S s2 = new SBuilder02().getS();
S s3 = new SBuilder03().getS();
}
那程序肯定不能这样写,扩展性太差了。为了改进,首先,肯定得先把这些建造者,给抽象出一个接口——SBuilder,用户就只需要依赖这个接口:
public static void main(String[] args) {
SBulider sBulider = new SBulider01();
S s = sBulider.getS();
System.out.println(s.toString());
}
虽然不同的建造者,可以得到不同属性的A,B,C,但如果ABC对象的构造,并不是这么简单的调用三个build方法,而是有一定的顺序和时机,那么每个建造者实现类,在getS()方法里,就要去做更多的事情,如果构造的过程过于繁琐,那么内聚性就会降低。这时就要"Director"类出场了,它就是专门负责这些内部对象的组装的:
class Director
{
SBuilder sBuilder;
public Director(SBuilder sBuilder)
{
this.sBuilder=sBuilder;
}
public S getS()
{
sBuilder.buildA();
sBuilder.buildB();
sBuilder.buildC();
return sBuilder.getS();
}
}
Director类内部有一个建造者实例,自己的getS()方法,做的就是把构建对象的过程给放进来。这样具体建造者的getS()方法,就只需要返回s对象就好了。
此时,用户类想要使用S对象,就变成了这样:
public static void main(String[] args){
SBuilder sBuilder = new SBuilder01();
Director director = new Director(builder);
S s = director.getS();
System.out.println(s.toString());
}
总结
可以看出:所谓的复杂对象,一是复杂在对象内部的小对象,参数的复杂多样,二是把这些内部小对象组装起来,可能也是一个繁琐的过程。其中建造者这一角色,就解决了第一个问题,而导演这一角色,就解决了第二个问题。
再举一个现实的例子,想要一个手机,找到了一个组装厂,该厂可以熟练的把屏幕,芯片,电路板等器件组装到一起,但他不会造屏幕,也不会造芯片。所以他就让专业的手机零件制造商A去造。而A商,就只造芯片,屏幕这些部件,不管如何组装。如果造的不满意,也可以让B制造商来造,总之,组装厂只负责组装,而制造商只负责制造,从而实现解耦。