舞步者

带她一起去周游世界
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

设计模式之二AbstractFactory模式

Posted on 2008-05-19 14:48  Kevin_Zhang  阅读(159)  评论(0)    收藏  举报

解决常规创建对象(如: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模式共同组合来应付对象创建的变化