解决常规创建对象(如:Road road=New Road(); )出现的问题:实现依赖,不能应对具体实例化类型变化。个人通俗的理解:如果将来关于“路”的问题有了变化,比如出现水泥路,沥青路,那么我们项目中所有出现上述语句的地方就得重新改变,即由于依赖于路的具体实现,而产生的问题
解决的思路:将变化点封装(哪里变化,就封装哪里);当然如果无变化或变化周期很慢,那么不必进行额外的封装(如String类,其已经很稳定了,当然不要封装)。
对于此类问题,我们发现变化点在对象创建,那么我们就封装对象创建
在实现过程中,我们依赖于接口,而不依赖于实现。
一.
1.简单的实现
class RoadFactory
{
public static Road CreateRoad()
{
return new WaterRoad();//将来路的类型有变化时,比如换成沥青路时,只要改这里就可以
}
}
abstract class Road
{
}
class WaterRoad:Road
{
}
//*******************************
客户程序
Road road=RoadFactory.CreateRoad();//这里我们就不需要改
二.
上述解决不能应对不同系列对象的变化;比如有不同风格的游戏场景--古典风格时的道路,房屋,地道;现代风格时的相应的情形
class RoadFactory {
public static Road CreateRoad()
{
return new Road();//考虑Road是抽象类的情形
}
public static Building CreateBuilding ()
{
return new Building();//考虑Building 是抽象类的情形,下同
}
public static Tunnel CreateTunnel ()
{
return new Tunnel();
}
public static Jungle CreateJungle()
{
return new Jungle();
}
}
//**************客户程序********
Road road=roadFactory.CreateRoad();
…
Building building=roadFactory.CreateBuilding();
上面的代码说明了这样的问题,当面对不同的场景的变化时,这样的代码就无能为力了;
当然如果我们可以不改变RoadFactory 的实现,另外再加另外几个RoadFactory类,如RoadFactoryA,以代表不同的场景情绪,那么此时问题又产生了,当将来有不同的场景时,客户程序这里又是变化点了...
解决方法:使用面向对象的技术封装变化点。
三.
动机:
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
如果,只涉及一个系列,那么静态工厂模式完全可以应付,在涉及多系列的相互依赖的对象时候,我们可以使用抽象工厂模式。
结构图:

以此图为类,客户程序(Client)只依赖于三个抽象类:AbstractFactory,AbstractProductA,AbstractProductB(抽象)。
类ConcreateFactory1和ConcreateFactory2作为不同的场景类(实现)。
类ProductA2,ProductA1,ProductB2,ProductB1是具体的类的实现。
下面以ThinkPad两个不同型号T43和T60为例,说明抽象工厂模式的具体应用;因为同一个系列中的CUP和主板互相依赖,所以组装的时候只能拿同一系列的产品进行组装
说明要点:
1.问题涉及不同型号的相互依赖的CPU和主板对象,所以我们将CPU和主板抽象出来,做成两个抽象类:
public abstract class Cpu
{
}
public abstract class MainBoard
{
}
2.然后具体型号的CPU和主板分别从这两个抽象类继承:
public class T43Cpu : Cpu
{
}
public class T60Cpu : Cpu
{
}
public class T43MainBoard : MainBoard
{
}
public class T60MainBoard : MainBoard
{
}
即:上面的代码实现了上图中的右边的部分
3. 单个的部件部分,是一个变化点,我们将其封装起来,做法和“一”很相似;下面开始涉及到具体型号的部件的组装问题;由于我们这里涉及T43和T60两个型号,将来也可能涉及到更多的系列,那么这里也是一个变化点,我们也应该进行封装,试想一下,如果我们这里不进行封装的处理,那么所出的问题跟我们在“二”里面提出的问题是不是如出一辙?也就是我们直接建立T43Factory和T60Factory这两个类,里面包含了具体的实现,那么将来在我们的客户代码里面是不是会出现这样的代码:
Cpu cpu=T43Factory.CreateCpu();
MainBoard mainBoard=T43Factory.CreateMainBoard();
那么将来型号改变的时候,我们这些代码是不是都要改变呢?答案是肯定的
所以我们当然应该将创建型号的操作进一步抽象出来,做成一个抽象的ThinkPadFactory类,让具体的型号的实现类来继承并实现其抽象方法;这样,我们客户代码所依赖的再也不是那些具体的型号类了(如T43Factory),所依赖的就是ThinkPadFactory这个抽象类。代码如下:
public abstract class ThinkPadFactory
{
public abstract Cpu CreateCpu();
public abstract MainBoard CreateMainBoard();
}
public class T43Factory:ThinkPadFactory
{
public override Cpu CreateCpu()
{
return new T43Cpu();
}
public override MainBoard CreateMainBoard()
{
return new T43MainBoard();
}
}
public class T60Factory : ThinkPadFactory
{
public override Cpu CreateCpu()
{
return new T60Cpu();
}
public override MainBoard CreateMainBoard()
{
return new T60MainBoard();
}
}
//上边的代码实现了结构图中的左边的部分
4.客户代码:
static void Main(string[] args)
{
Program p = new Program();
p.CreateThinkPad("T43").Run();
}
public ThinkPad CreateThinkPad(string thinkpadName)
{
ThinkPadFactory thinkpadFactory=(ThinkPadFactory)Assembly.Load("AbstractFactory").CreateInstance("AbstractFactory." + thinkpadName + "Factory");
Cpu cpu=thinkpadFactory.CreateCpu();
MainBoard mainboard = thinkpadFactory.CreateMainBoard();
return Assemble(cpu, mainboard);
}
public ThinkPad Assemble(Cpu cpu, MainBoard mainboard)
{
//......省略组装过程
return new ThinkPad();
}
几个注意点:
1.如果没有应对“多系列对象构建”的需求变化,那么没有必要使用Abstractory Factory,简单的静态工厂完全可以
2.此模式在应对有单个新对象要求时,比如上例又要添加一个硬盘对象,那么此时此模式
不再适用
3.为解决2中提出的缺陷,那么抽象工厂模式常和Factory Method模式共同组合来应付对象创建的变化
浙公网安备 33010602011771号