网页访问计数器

设计模式笔记(3)---抽象工厂模式(创建型)

Gof定义

提供一个借口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定他们具体的类。

动机

在软件系统中经常面临着一系列相互依赖的对象的创建的工作,同时由于需求的变化,往往存在着更对系列对象的创建。

常规的对象创建的方法,直接使用new关键字

Road road = new Road();

这样直接new会有一个问题,不能应对具体实例化类型的变化,比如说有不同的Road类型需要被实例化的时候就需要来更改此处的代码。解决这个问题的办法就是封装变化点,变化点也是相对而言的,比如在项目中有些地方会经常更具客户的需求而作改动,我们就可以将其封装起来。拿上面的那行代码来说,因为可能有不同类型的Road需要被创建,变化点就是“对象的创建”。

一种比较简单的解决方法,看下面的代码

public class RoadFactory
{
    public static Road CreateRoad()
    {
        return new Road();
    }
}

 

//调用的代码
public class Test
{
    static void Main(string[] args)
    {
        Road road = RoadFactory.CreateRoad();
    }
}

现在需求有了改变,需要创建一种另一种类型的路HighRoad,只需更改工厂类的代码就可以,调用的地方不用做修改,如下

public class RoadFactory
{
    public static Road CreateRoad()
    {
        return new HighRoad();
    }
} 

现在需求又有了改变,比如在游戏的开发场景中,我们需要构建道路、房屋、丛林等等对象,按照上面的思路我 可以写成下面这样的代码

//客户程序
  public class Test
  {
      static void Main(string[] args)
      {
          Road road = GameObjectFactory.CreateRoad();
          Building building = GameObjectFactory.CreateBuilding();
          Jungle jungle = GameObjectFactory.CreateJungle();
      }
  }
  
  public class GameObjectFactory
  {
      public static Road CreateRoad()
      {
          return new Road(); 
      }
      public static Building CreateBuilding()
      {
          return new Building();
      }
      public static Jungle CreateJungle()
      {
          return new Jungle();
      }
  }

以上的代码属于一种简单工厂的实现,将对象的创建放到一个单独的工厂类中,实现了和客户程序的分离,不过 不能应对不同系列对象的变化,比如有不同风格的游戏场景,对于要实现不同风格场景中的道路、房屋等对象的 创建,上面的代码就难以实现。对于有不同系列对象这样的需求,变化点转移到了工厂类的内部,上面的代码中 对象的创建是在工厂类中的静态方法中写死的,不能应对变化,如果我们另外创建一个能适应其他系列的工厂类, 那么客户程序就会发生改变,这不是我们希望看到的。要解决此类问题必须使用面向对象的技术来封装变化点。

结构图

2009-09-28_220757

上面的结构图中AbstractFactory为创建对象的抽象工厂类,AbstractProductA、AbstractProductB为具 体对象的抽象类,拿到上面的例子中就是道路、房屋、丛林等的抽象。他们的子类ProductA1、ProductB1就是 指不同风格系列的是实现,这也正是抽象工厂模式要解决的问题。图中还可以看出客户程序依赖的是抽象的部分 而没有涉及到具体的实现,也就是说当需求改变的时候,客户程序是不用变的。下面就来看代码是如何实现。

首先创建抽象工厂类

public abstract class FacilitiesFactory
{
    public abstract Road CreateRoad();
    public abstract Building CreateBuilding();
    public abstract Jungle CreateJungle();
}

因为游戏场景中有道路、房屋、丛林这三种对象,需要创建这三个对象的抽象类,如果有更多的对象,需要增加其他对象的抽象类。

//道路
public abstract class Road
{ 

}
//房屋
public abstract class Building
{ 

}
//丛林
public abstract class Jungle
{ 

}

下面的客户程序代码都是对抽象类之间的操作

//客户程序
public class GameManage
{
    FacilitiesFactory _facilitiesFactory;
    Road _road;
    Building _building;
    Jungle _jungle;
    public GameManage(FacilitiesFactory facilitiesFactory)
    {
        _facilitiesFactory = facilitiesFactory;
    }

    /// <summary>
    /// 创建一些基础设施的对象
    /// </summary>
    public void BuildGameFacilities()
    {
        _road       = _facilitiesFactory.CreateRoad();
        _building   = _facilitiesFactory.CreateBuilding();
        _jungle     = _facilitiesFactory.CreateJungle();
    }

    public void Play()
    { 
        //执行一些操作
    }
}

在应用程序中使用上面的代码

public class App
{
    static void Main()
    {
        GameManage g = new GameManage(
?
);
        g.BuildGameFacilities();
        g.Play();
    }
}

上面的代码中?的地方应该传入什么参数呢?从GameManage类的构造函数中可以看出是一个抽象工厂类型,大 家都知道,抽象类是不能创建实例的,所以问号的地方应该是AbstractFactory类的子类。假设现在有一个现代 风格系列的游戏场景,就需要创建一组现在的道路、房屋、丛林,如下:

//道路
public class ModernRoad:Road
{

}
//房屋
public class ModernBuilding:Building
{

}
//丛林
public class ModernJungle:Jungle
{

}

下面创建现代风格的工厂类

public class ModernFacilitiesFactory:FacilitiesFactory
{
    public override Building CreateBuilding()
    {
        return new ModernBuilding();
    }
    public override Road CreateRoad()
    {
        return new ModernRoad();
    }
    public override Jungle CreateJungle()
    {
        return new ModernJungle();
    }
}

现在App类的代码可以改成如下

public class App
{
    static void Main()
    {
        GameManage g = new GameManage(new ModernFacilitiesFactory());
        g.BuildGameFacilities();
        g.Play();
    }
}

结构图

2009-09-28_234052

如果有新的需求,需要一套古典风格或者是梦幻风格的的游戏场景,只需要

1 创建一套新的相应风格的对象继承道路、房屋、丛林等的抽象类

2 创建一个相应风格的工厂继承抽象工厂

3 App类中调用的地方给GameManage类传入相应的工厂类的实例。

整个过程中,只是在外部扩展一些类,GameManage并没有做任何的改变

抽象工厂模式的几个要点:

  • 如果没有对应多系列对象构建的需求变化,没有必要使用抽象工厂模式,使用静态工厂完全可以达到要求
  • 系列对象指的是这些对象之间的相互依赖,或作用的关系,如游戏开发场景中的道路与房屋的依赖等
  • 抽象工厂模式主要在于应对新系列的需求变动。其确定在于难以应对新对象的变动
  • 抽象工厂模式经常和工厂方法模式组合起来使用,来应对对象创建的需求变化

返回开篇(索引)

posted @ 2009-11-21 01:09  oec2003  阅读(671)  评论(1编辑  收藏  举报