代码改变世界

C#面向对象设计模式纵横谈 笔记3 抽象工厂(创建型模式)

2011-06-13 08:35  lujiao_cs  阅读(388)  评论(2编辑  收藏  举报

new的问题

常规的对象创建方法: 

      // 创建一个Road 对象 

      Road road=new Road(); 

new的问题:

      –  实现依赖,不能应对具体实例化类型的变化。

解决思路: 

      –  封装变化点(学习设计模式的核心)—— 哪里变化,封装哪里 

      –  潜台词:如果没有变化,当然不需要额外的封装!

业务对象变化频繁,就对它进行封装。

 

工厂模式的缘起

1)变化点在对象创建,因此就封装对象创建” 

2)面向接口编程——依赖接口,而非依赖实现(可以实现松耦合)

3)最简单的解决方法:


///这里是类库:Road经常变化,所以封装起来。
class MyFactory {
public static Road CreateRoad() //静态方法
{
return new Road();
     
//如果对路的需求有变化,需要返回一个水路
    
//比如:将Road变为一个抽象类。将改变隔离在这里。
    
//return new WaterRoad(); WaterRoad 继承自Road。(一定程度上解决了问题)
}
}
-----------------------------------------------------------------------------------------------
// 这里是客户程序:创建一个Road 对象。
Road road = MyFactory .CreateRoad();


创建一系列相互依赖的对象

我们假设一个游戏开发场景:                    

 

我们需要构造道路房屋地道丛林”……等等对象

这些对象之间有交互,相互依赖。比如:需要在丛林下面挖地道

//一个简单的静态工厂
class MyFactory {
  
public static Road CreateRoad()
  {
    
return new Road();
  }
  
public static Building CreateBuilding ()
  {
    
return new Building();
  }
  
public static Tunnel CreateTunnel ()
  {
    
return new Tunnel();
  }
  
public static Jungle
  {
    
return new Jungle();
  }
}

-------------------------------------------------------------------------------------------

//下面的代码相对稳定
Road road = MyFactory .CreateRoad();
Building building
= MyFactory .CreateBuilding();

 

简单工厂的问题

简单工厂的问题: 

    –  不能应对不同系列对象的变化Class MyFactory 成为变化点)。比如有不同风格的游戏场景——对应不同风格的道路、房屋、地道

如何解决: 

    –  使用面向对象的技术来封装变化点

 

动机(Motivation

   在软件系统中,经常面临着“一系列相互依赖的对象的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作(如果是一个系列,使用静态工厂RoadFactory 就足够了,不需要使用抽象工厂。面临“多系列对象”:使用抽象工厂)。

 

   如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和这种多系列具体对象创建工作紧耦合避免:客户程稍微一点改变,类库就要产生很大的变化。

 

意图(Intent

提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类。 (注:这句话描述了抽象工厂的结构,没有完整的将抽象工厂的深意表达出来。)

                                               ——  《设计模式》GoF 

结构(Structure) (客户程序直接依赖的是与红色框的抽象类)

 

打比方:ConcreateFactory1为现代风格工厂,ConcreateFactory2 为古典风格下的工厂。

  A1 B1相互依赖(现代风格下的道路和房屋),ProductA1ConcreateFactory1CreateFactoryA()方法创建,ProductB1ConcreateFactory1CreateFactoryB()方法创建。

  A2B2相互依赖(古典风格下的道路和房屋),ProductA1ConcreateFactory1CreateFactoryA()方法创建,ProductB1ConcreateFactory1CreateFactoryB()方法创建。

注意:A1B2不是相互依赖,A2B1不是相互依赖。

 

代码:

/// <summary>
/// 抽象道路:AbstractProductA
/// </summary>
public abstract class Road
{
public void AAA();
}
/// <summary>
/// 抽象房屋:AbstractProductB
/// </summary>
public abstract class Building
{
public void BBB();
}
/// <summary>
/// 抽象地道:AbstractProductC
/// </summary>
public abstract class Tunnel
{
public void CCC();
}
/// <summary>
/// 抽象丛林:AbstractProductD
/// </summary>
public abstract class Jungle
{

}
/// <summary>
/// 设施抽象工厂:AbstractFactory
/// </summary>
abstract class FacilitesFactory
{
public abstract Road CreateRoad();
public abstract Building CreateBuilding();
public abstract Tunnel CreateTunnel();
public abstract Jungle CreateJungle();
}
/// <summary>
/// 现代风格的道路
/// </summary>
public class ModernRoad : Road
{

}
/// <summary>
/// 现代风格的房屋
/// </summary>
public class ModernBuilding : Building
{

}
/// <summary>
/// 现代风格的地道
/// </summary>
public class ModernTunnel : Tunnel
{

}
/// <summary>
/// 现代风格的丛林
/// </summary>
public class ModernJungle : Jungle
{

}
/// <summary>
/// 现代风格的设施工厂
/// </summary>
public class ModernFacilitesFactory : FacilitesFactory
{
public override Road CreateRoad()
{
return new ModernRoad();
}
public override Building CreateBuilding()
{
return new ModernBuilding();
}
public override Tunnel CreateTunnel()
{
return new ModernTunnel();
}
public override Jungle CreateJungle()
{
return new ModernJungle();
}
}
/// <summary>
/// 客户程序:它是稳定的
/// </summary>
class GameManager
{
FacilitesFactory facilitesFactory;
Road road;
Tunnel tunnel;
Building build;
Jungle junngle;

public GameManager(FacilitesFactory _facilitesFactory)
{
facilitesFactory
= _facilitesFactory;
}

/// <summary>
/// 产生游戏设施
/// </summary>
public void BuildGameFacilites()
{
//依赖的都是抽象类部分
road = facilitesFactory.CreateRoad();
tunnel
= facilitesFactory.CreateTunnel();
build
= facilitesFactory.CreateBuilding();
junngle
= facilitesFactory.CreateJungle();
}
/// <summary>
/// 运行游戏
/// </summary>
public void Run()
{
road.AAA();
tunnel.CCC();
}
}
//调用
class Program
{
static void Main(string[] args)
{
///构件一个现代的风格的游戏程序。
GameManager g = new GameManager(new ModernFacilitesFactory());
g.BuildGameFacilites();
g.Run();
}
}


Abstract Factory模式的几个要点 

  如果没有应对多系列对象构建的需求(需要各种古典、现代等不同风格)变化,则没有必要使用Abstract Factory模式,这时候使用简单的静态工厂完全可以。 

  “系列对象指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的道路房屋的依赖,道路” 地道的依赖。 

  Abstract Factory模式主要在于应对新系列的需求变动(风格的变化:现代的、古典的)。其缺点在于难以应对新对象的需求变动。注:如果需求是要创建各种的新的对象,比如沙漠、河、大海等,就变成误用了。具体要看需求的变化点。

  Abstract Factory模式经常和Factory Method模式共同组合来应对对象创建的需求变化。 

 

 

 

推荐参考书 

•    《设计模式:可复用面向对象软件的基础》GoF 

•    《面向对象分析与设计》Grady Booch 

•    《敏捷软件开发:原则、模式与实践》Robert C. Martin 

•    《重构:改善既有代码的设计》Martin Fowler 

•    Refactoring to PatternsJoshua Kerievsky