抽象工厂模式和Builder模式
最近要参加面试,于是乎又把设计模式拿出来过了一遍.由于每次在看到抽象工厂和Builder模式的时候总是有点迷糊,因此这次下了狠心,翻箱倒柜的找出英文版教材,中英对照,希望能把这两种模式搞清楚.
所有的创建型模式的本质目的都是为了更好的创建对象,抽象工厂和Builder模式也是如此,另外,两种模式还有一个共同的特点,就是将对象创建过程与使用过程相分离,用户在使用时只需知道该创建什么,而无需知道对象是究竟如何创建的.这样对象创建和使用的过程之间就呈现一种松耦合的形式,当创建过程有改动的时候只需对创建过程进行无需对使用过程作出任何修改.除此之外,两种模式同样都是被用于将部件对象构造成一个完整的对象.举个例子,某工厂生产IBM电脑和HP电脑,两种电脑的配置不相同,但都是由CPU、主板、内存、硬盘等部件构成,工厂模式和Builder模式都可以根据不同的配置生成IBM电脑或者HP电脑。
两种模式的共同点使得在刚刚开始学习的时候,非常容易混淆,其实仔细研究,两者之间的区别也是非常明显的,而我认为两者之间最本质的区别是,抽象工厂通过不同的构建过程生成不同的对象表示,而Builder模式通过相同的构建过程生成不同的表示。
上面的文字比较抽象,下面举个例子说明。
假设有具体工厂类IBMFactory,HPFactory和具体对象类IBM,HP,其中工厂类继承自AbstractFactory类,工厂类实现方法GetProduct(),具体对象类继承自Computer类,对象类实现方法Attach()用于装配不同部件,设部件都继承自基类Component,演示代码如下:
{
abstract public Computer GetProduct(); //抽象方法
}
class IBMFactory:AbstractFactory //生产IBM电脑
{
public Computer GetProduct()
{
IBM ibm=new IBM();
ibm.Attach(new IBM所需CPU); //装配CPU
ibm.Attach(new IBM所需主板); //装配主板
ibm.Attach(new IBM所需内存); //装配内存
ibm.Attach(new IBM所需硬盘); //装配硬盘
return ibm; //返回构建好的对象
}
}
class HPFactory:AbstractFactory() //生产HP电脑
{
public Computer GetProduct()
{
HP hp=new HP()
hp.Attach(new HP所需CPU); //装配CPU
hp.Attach(new HP所需主板); //装配主板
hp.Attach(new HP所需内存); //装配内存
hp.Attach(new HP所需硬盘); //装配硬盘
return hp; //返回构建好的对象
}
}
abstract class Computer //基类
{
abstract public void Attach(Component component);
}
class IBM:Computer
{
public void Attach(Component component)
{
装配IBM部件
}
}
class HP:Computer
{
public void Attach(Component component)
{
装配HP部件
}
}
使用的过程如下:
IBMFactory ibmFactory=new IBMFactory(); //实例化IBM工厂
IBM ibm=(IBM)ibmFactory.GetProduct(); //生成IBM对象
HPFactory hpFactory=new HPFactory(); //实例化HP工厂
HP hp=(HP)hpFactory.GetProduct(); //生成HP对象
从上面代码可以产出,IBM电脑的构建过程是由IBMFacotry实现的,而HP的构建过程是由HPFactory实现的,当我想要生产某种计算机的时候需要首先实例化对应的工厂,然后通过工厂的GetProduct()方法装配出需要的对象。
也即,创建不同的对象需要不同的创建过程。
下面再来看,采用Builder模式是如何描述上述生产过程的。在Builder模式中有两个重要的对象,一个叫做Builder,一个叫做Director,其中Builder对象负责描述对象的构造细节,Director负责构造完整的对象。假设有具体Builder类IBMBuilder,HPBuilder以及Director类Director,其中Builder类对象的基类为Builder,Builder中有方法Building(),Director类有方法Construct()和GetComputer()方法,代码如下:
Computer,IBM,HP类描述同上。
{
abstract public Computer Building();
}
class IBMBuilder //IBM对象的创建者
{
public Computer Building()
{
IBM ibm=new IBM();
ibm.Attach(new IBM所需CPU); //装配CPU
ibm.Attach(new IBM所需主板); //装配主板
ibm.Attach(new IBM所需内存); //装配内存
ibm.Attach(new IBM所需硬盘); //装配硬盘
return ibm; //返回构建好的对象
}
}
class HPBuilder //HP对象的创建者
{
public Computer Building()
{
HP hp=new HP()
hp.Attach(new HP所需CPU); //装配CPU
hp.Attach(new HP所需主板); //装配主板
hp.Attach(new HP所需内存); //装配内存
hp.Attach(new HP所需硬盘); //装配硬盘
return hp; //返回构建好的对象
}
}
class Director //指导者类
{
protected Computer computer=null; //保存具体对象
public void Construct(Builder builder) //创建具体对象
{
computer=builder.Building();
}
public Computer GetComputer() //获取已经创建好的对象
{
return computer;
}
}
使用过程如下:
IBMBuilder ibmBuilder=new IBMBuilder(); //实例化IBM创建者对象
HPBuilder hpBuilder=new HPBuilder(); //实例化HP创建者对象
Director director=new Director(); //实例化创建者对象
director.Construct(ibmBuilder); //创建IBM对象
IBM ibm=(IBM)director.GetComputer(); //获取IBM对象
irector.Construct(hpBuilder); //创建HP对象
HP hp=(HP)director.GetComputer(); //获取HP对象
从上面代码可以看出,IBM和HP对象的创建过程均有Director的Constuct()实现,只要设置不同的Builder,就可以创建不同的对象。也即,用相同的创建过程创建不同的对象。
直观上的感觉,Builder模式是抽象工厂模式的再封装,不但实现了创建过程的隐藏,甚至连创建过程该有那个方法实现都不必再去考虑,这样我们可以更加黑盒的去构建不同的对象。但事实上,两种模式有本质的区别,Builder模式的使用前提是被创建的对象之间有紧密的关系,属于同一类对象,当组成对象类型不同的时候,Builder模式就显得力不从心了,这是就需要配合抽象工厂模式来构建由不同类型的对象构成的对象了。