【转】设计模式学习笔记(3)-工厂方法

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

怎样理解这句话呢?在程序编写中为了实现代码的复用,我们往往会采用继承的方式来完成。设计一个父类,父类中有一些公用的方法可以提供给子类使用,但子类往往差距较大,这时我们在父类会采用
一种虚构造器(Vitual Constructor),即工厂方法来实现。

举个例子,我们有一个面包生产流水线,这涉及到两个部分:面包的生产与包装。不同面包的包装流程往往是相同的,但制作工艺却差距
巨大,黑面包和白面包采用的原料肯定是不一样的。这种情况下怎么办呢?流水线要工作离不开面包的生产啊,但面包的生产又涉及到子类具体的实现。我们想到能否让具体面包的初始化延迟到子类呢?
这实际上就是懒加载(Lazy load)


这里可以实现的工厂方法模式如下:
FactoryMethod

这里Bread是抽象类,它有两个子类:WhiteBread和BlackBread。BreadFactory也是抽象类,其中createBread方法是纯虚函数,必须由子类来实现,它的两个子类是WhiteBreadFactory和BlackBreadFactory。

我们可以简单地看一下他们的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Bread
{
public :
    virtual void color() = 0;
};
class WhiteBread : public Bread
{
public:
    void color()
    {
        cout << "this bread is white!" << endl;
    }
};
class BlackBread : public Bread
{
    void color()
    {
        cout << "this bread is black!" << endl;
    }
};

我们在面板类中定义了color方法以返回面包的颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class BreadFactory
{
public:
    virtual Bread* createBread() = 0;
    virtual void wrapBread(Bread* bread)
    {
        cout << "I'm wrapping the bread; " << bread->color();
    }
    virtual void go()
    {
        this->wrapBread(this->createBread());
    }
};
class WhiteBreadFactory : public BreadFactory
{
public:
    Bread* createBread()
    {
        return new WhiteBread;
    }
};
class BlackBreadFactory : public BreadFactory
{
public:
    Bread* createBread()
    {
        return new BlackBread;
    }
};

在工厂方法中调用go方法可以实现面包的生成和打包,而面包的生成全部下放到具体子类来实现。我们在主方法中写道:

1
2
BreadFactory* factory = new WhiteBreadFactory();
factory->go();

最终屏幕输出为:

1
I'm wrapping the bread this bread is white!

如果我们要生成黑面包只需将代码改为下面这样就行了。

1
BreadFactory* factory = new BlackBreadFactory();

我们来回顾一下刚刚发生了什么。我们新建了一个抽象工厂,由其子类WhiteBreadFactory来实例化。当我们调用factory->go()时,程序会调用BreadFactory中的go方法,发现其是一个纯虚函数,于是寻找其实现
类中的方法,实现类返回了一个WhiteBread对象,于是程序继续执行到wrapBread方法,wrapBread方法是一个虚函数(不是必须的),在子类中没有重载,于是执行父类的wrapBread函数。最终打印结果。

利用工厂方法模式我们能做些什么呢?
当我们添加新的面包如YellowBread时,只需添加一个YellowBread实现类和一个工厂类即可。如果我们想在createBread方法中添加一些新的内容如加黄油等等只需在子类中编写就行了。这种改变十分灵活,而且有个专业术语叫做:钩子(hook)。
GoF还提到了一个概念:平行的类层次。是指如果一个类将它的一些职责委托给一个独立的类的时候,便产生了平行类层次。如本例中WhiteBread和WhiteBreadFactory就是一个平行的类,BlackBread和BlackBreadFactory也是一个平行的类层次。
而工厂方法模式为连接了平行的类层次,使得类的责任分工明确。

如果仔细看我们的代码,会发现有些重复:BlackBreadFactory和WhiteBreadFactory只有返回值不同。很自然地我们想到可以采用C++等语言提供的模版机制来消除重复。

1
2
3
4
5
6
7
8
9
template
class NewBreadFactory : public BreadFactory
{
public:
    T* createBread()
    {
        return new T;
    }
};

在主方法中这样写:

1
BreadFactory* factory = new NewBreadFactory();

输出结果是一样的。这样以后添加新的面包只需编写继承Bread类的子类就行了。

惯例我们看看工厂方法模式的适用性:

  • 当一个类不知道它所创建的对象的类的时候
  • 当一个类希望由它的子类来指定它所创建的对象的时候
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理这这一信息局部化的时候

工厂方法模式和前面所说的抽象工厂模式有什么联系和区别呢?抽象工厂模式使用了工厂方法模式,工厂方法模式更普遍一点,两者并不存在冲突。

 

原文链接:http://lecoding.com/articles/93.html

posted on 2013-03-05 13:45  TheKingOfKingFish  阅读(126)  评论(0)    收藏  举报

导航