设计模式(3) 工厂方法(Factory Mehod)

问题聚焦:
工厂方法与抽象工厂的区别
别名:虚构造器(Virtual Constructor)

意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

别名:
虚构造器,Virutal Constructor

动机:依然用一个实例来说明

Demo
考虑一个应用框架,它可以向用户显示多种文档。
两个抽象:Application(管理和创建Document),Document
例如绘图应用:DrawingApplication,DrawingDocument
特点:因为被实例化的特定Document子类是与特定应用相关的,所以Application类不可能预测到哪个Document子类将被实例化。
解决方案:封装哪一个Document子类将被创建的信息,并将这些信息从该框架中分离出来。
架构:

Application的子类重定义Application的抽象操作CreateDocument以返回适当的Document子类对象,一旦一个Application子类实例化以后,它就可以实例化与一个用相关的文档,而无需知道这些文档的类。


适用性
  • 下列情况考虑使用Factory Method模式
  • 当一个类不知道它所必须创建的对象的类的时候
  • 当一个类希望由它的子类来指定它所创建的对象的时候
  • 当类创建对象的职责委托给多个帮助子类的某一个,并且你希望哪一个帮助子类是代理者这一信息局部化的时候
结构


参与者
  • Product(Document): 定义工厂方法所创建的对象的接口
  • ConcreteProduct(MyDocutment): 实现Product接口
  • Creator(Application):声明工厂方法,返回一个Product类型的对象,Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteProduct对象;可以调用工厂方法以创建一个Product对象
  • ConcreteCreator(MyApplication):重定义工厂方法以返回一个ConcreteProduct实例
协作
Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的ConcreteProduct实例

效果
不再将与特定应用相关的类绑定到你的代码中,代码仅处理Product接口
为子类提供挂钩:用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活
连接平行的类层次:工厂方法往往并不只是被Creator调用,客户可以找到一些有用的工厂方法。
解析:
平行类层次:当一个类将它的一些职责委托给一个独立的类时,就产生了平行类层次。
考虑一个例子
功能:对一个图形,用鼠标进行伸展、移动或者旋转
难点:需要存储和更新在给定时刻操作状态的信息;不同的图形有不同的行为
设计:Figure(图形类)、Manipulator(操作类,实现交互,保存操作相关状态)

从Client的角度看,操作类层次和图形类层次是平行的。
Figure类提供一个CreateManipulator工厂方法,它使得客户可以创建一个与Figure相对应的Manipulator。

实现
1 当应用工厂方法模式时要考虑下面的问题:
两种不同的情况
Creator类是一个抽象类,并且不提供它所声明的工厂方法(必须实例化子类才能使用)
Creator类是一个具体类,而且为工厂方法提供一个缺省的实现()
2 参数化工厂方法
工厂方法支持传递参数来创建多种产品
Demo
 一个参数化的工厂方法具有如下的一般形式
class Creator {
public:
    virtual Product* Creator(ProductId);
};

Product* Creator::Create (ProductId id) {
    if (id == MINE) return new MyProduct;
    if (id == YOURS) return new YourProduct;
    return 0;
}

// 子类MyCreator继承Creator
product* MyCreator::Create (ProductId id)
{
    if (id == YOURS) return new MyProduct;
    if (id == MINE) return new YourProduct;
    if (id == THEIRS) return new TheirProduct;

    return Creator::Create(id);    // 如果都不匹配,返回父类的Create
}
3 特定语言的变化和问题
在C++中记住一点,不要在Creator或者其子类的构造器中调用工厂方法。
访问者希望或得产品时,访问者首先检查一下该产品是否存在,如果产品不存在,访问者就创建它。这种技术称为lazy initialization。
4 使用模板以避免创建子类
工厂方法的一个潜在问题就是,可能仅为了创建适当的Product对象而迫使你创建Creator子类。(当然,可以用参数化工厂方法来解决这个问题)
另一个解决办法:提供Creator一个模板子类,使用Product类作为模板参数。
class Creator {
public:
    virtual Product* CreateProduct() = 0;
};

template <class TheProduct>
class StandardCreator: public Creator {
public:
    virtual Product* CreateProduct() ;
}

template <class TheProduct>
Product* StandardCreator<TheProduct>::CreateProduct() {
    return new TheProduct;
}

// 使用这个模板
class MyProduct : public Product {
public:
    MyProduct();
    // ......
};

StandardCreator<MyProduct> myCreator;
5 命名约定
命名以清楚地说明你正在使用工厂方法


代码示例
使用工厂方法建造一个迷宫,使子类可以选择这些构件。每一个工厂方法返回一个给定类型的迷宫构件。
class MazeGame {
public:
    Maze* CreateMaze();

    virtual Maze* MakeMasze() const
        { return new Maze;}
    virtual Room* MakeRoom(int n) const
        { return new Room(n) };
    virtual Wall* MakeWall() const
        { return new Wall;}
    virtual Door* MakeDoor(Room* r1, Room* r2) const
        { return new Door(r1, r2); }
}

不同的游戏可以创建MazeGame的子类,以特别指明一些迷宫的部件。MazeGame子类可以重定义一些或所有的工厂方法以指定产品中的变化。
如:
class BombedMazeGame: public MazeGame {
public:
    BombedMazeGame();
    
    virtual Wall* MakeWall() const
        { return new BombedWall; }
    virtual Room* MakeRoom(int n) const
        { return new RoomWithABomb(n); }
};


相关模式
Abstract Factory经常用工厂方法实现;
在Template Method中被调用
Prototypes不需要创建Creator的子类,但是它们通常要求一个针对Product类的Initialize操作。Creator使用Initialize来初始化对象,而Factory Method不需要这样的操作。



参考资料:
《设计模式》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值