设计模式介绍之五:工厂模式(factory)

    我们在实现一个软件系统时,经常遇到添加新类型的情况,没有设计模式经验的开发者会采取比较直接的方式,定义一个类,在用这个类的模块中引入该类所在的头文件,使用 new 操作符从堆上分配一个对象,不需要的时候调用 delete 来删除对象回收内存。随着类型越来越多,这种分配对象的操作遍布代码各个模块,一旦类的定义发生变化,尤其是修改或增加了新的接口,就要到处检查修改代码,系统大了,甚至会遗漏一些需要修改的地方,导致不可预期的结果。

    工厂模式就是用来解决上述问题的,它封装对象的创建,使得对象的创建集中在一个地方,添加新类型只需要改动这个地方,新的类型就会应用到系统中,甚至使用新类型的模块都不知道正在使用的是什么类型。

    当发现需要添加新的类型到一个系统中时,最明智的做法是用多态机制为这些新类型创建一个共同的接口。用这种方法可以将系统中其余的代码与新添加的特定类型的代码分开,新类型的添加不会扰乱已存在的代码。

    由于每个面向对象应用程序都需要创建对象,并且我们经常通过添加新类型来扩展应用程序,工厂模式可能是所有设计模式中最有用的模式之一。通过强制使用工厂模式,将创建对象的代码转到工厂执行,那么在增加新类型时所要做的全部工作就是只需要修改工厂。这将会大大降低因为类型增加导致的代码维护工作。

    这篇文章里我们介绍简单工厂模式。下面是《C++ 编程思想》一书第二卷的工厂模式的示例(去掉了异常处理部分):

class Shape{
public:
    virtual void draw() = 0;
    virtual void erase() = 0;
    
    static Shape * factory(const string& type);
};

class Circle : public Shape {
    Circle(){}
    friend class Shape;
public:
    void draw(){ cout << "Circle::draw" << endl;}
    void erase(){ cout << "Circle::erase" << endl;}
    ~Circle(){ cout << "Circle::~Circle" << endl;}
};

class Square : public Shape{
    Square(){}
    friend class Shape;
public:
    void draw() { cout << "Square::draw" << endl; }
    void erase() { cout << "Square::erase" << endl; }
    ~Square(){ cout << "Square::~Square" << endl; }
};

Shape * Shape::factory(const string& type)
{
    if(type == "Circle")
    {
        return new Circle();
    }
    if(type == "Square")
    {
        return new Square();
    }
    
    return NULL;
}

char* g_sl[] = { "Circle", "Square", "Square",
    "Square","Circle","Square"};
    
int main()
{
    vector<Shape*> shapes;
    for(int i = 0; i < sizeof(g_sl)/sizeof(g_sl[0]); i++)
        shapes.push_back(Shape::factory(g_sl[i]));
    for(int i = 0; i < shapes.size(); i++)
    {
        shapes[i]->draw();
        shapes[i]->erase();
    }
    return 0;
}

    函数 factory() 允许以一个参数来决定创建何种类型的 shape 。在添加新的 Shape 类型时,函数 factory() 是唯一需要修改的地方。但是这种实现——基类 Shape 必须了解每个派生类的细节——违反了面向对象设计的一个原则:基类不需要了解派生类。

    这种设计比较笨拙,因为一旦新类型被添加到这种层次结构中,基类就必须更新,这对于结构框架或者类库来说都是非常不合适的。

    可以通过一些策略来避免这种情况,下一次我将提供一个比较精巧的实现,利用 C++ 中类的构造函数,通过注册创建函数的方法,实现一个根据关键字创建对象的工厂模式。该工厂模式实现分离工厂、产品、产品创建过程,工厂不需要知道产品如何创建,有效地隔离了新类型添加对工厂的影响——工厂不需要做任何改动,最终做到新增类型只需要在实现新类型的地方添加代码,软件中的其他地方——连工厂——都不需要改变。

    回顾一下设计模式介绍系列的前几篇文章(接下来的工厂模式实现会用到单例、命令两个模式):


设计模式介绍之五:工厂模式(factory)

上一篇:Flash as3制作任意放大缩小旋转的变形工具


下一篇:C# 多线程编程之锁的使用【互斥锁(lock)和读写锁(ReadWriteLock)】