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相互依赖(现代风格下的道路和房屋),ProductA1由ConcreateFactory1的CreateFactoryA()方法创建,ProductB1由ConcreateFactory1的CreateFactoryB()方法创建。
A2和B2相互依赖(古典风格下的道路和房屋),ProductA1由ConcreateFactory1的CreateFactoryA()方法创建,ProductB1由ConcreateFactory1的CreateFactoryB()方法创建。
注意:A1和B2不是相互依赖,A2和B1不是相互依赖。
代码:
/// 抽象道路: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>
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>
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 Patterns》Joshua Kerievsky