简单工厂模式

简单工厂走一走~

虽然看 《设计模式-可复用面向对象软件的基础》 的时候,将工厂模式分为2种

  • 工厂方法模式
  • 抽象工厂模式

但是在看 《大话设计模式》 以及网上很多资料时,一般都习惯将 工厂方法模式 做了进一步的拆分,分为3种

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

这篇文章主要就是先从 简单工厂模式 入手,真正开发过程中用的最多的还是简单工厂模式

是什么

工厂的生产环境流程简化后一般是: 人提供给工厂 一个材料, 工厂 加工完成后,工厂给人 一个产品, 只要提供给工厂产品对应的材料,工厂可以加工各种各样的产品

简单工厂模式的流程其实也是这样的,我现在需要一个对象, 我提供给 “工厂” 一个材料(参数), “工厂” 根据材料(参数)生产对象, 最后将产品提供给我, 提供不同的材料(参数),工厂返回不同的产品

所以在这样的描述下,工厂最核心的功能就是 根据传入参数返回产品(对象),为了让客户端的 “我” 调用的更简洁,工厂类返回产品的接口设计成 static

接下来主要就是对这个 “产品” 进行设计,毕竟 “我” 操作的对象是工厂替我创建的 产品

对于 “我” 而言,不需要知道具体的产品是什么,所以设计一个产品的基类,具体的产品继承这个产品基类, 所以此时工厂返回给 “我” 一个基类的对象,我直接操作基类,而子类以父类的身份出现,这就很好的利用了C++多态这个属性,并且 “我” 是依赖于抽象的产品基类,也在一定程度解耦了

所以 简单工厂模式 的核心是下面几个点

  • 工厂下的产品都具有共同的属性
  • 一个工厂类即可,并且完成旗下所有的具体产品创建逻辑

优缺点

根据设计思路,其实不难发现它有以下几个优点:

  • 结构上,客户端负责要对象,工厂类负责提供对象,职责划分清晰
  • 代码上,客户端的我,不需要知道具体产品的类名,只需要知道参数即可,因此我的头文件只需要 include 基类,毕竟客户端操作的对象是基类的对象
  • 后期具体产品不论怎么添加,客户端这方面的代码基本都不需要进行大的修改,最多需要维护一个具体产品和提供给工厂的参数之间的关系表

优点很明显,缺点同样也很明显:

  • 工厂承担的职责太多了,负责了所有产品的创建逻辑,这就导致如果工厂类出现问题,影响的代码可能会很多
  • 并且当需要添加新的的产品时,就需要修改工厂类,而在很多开发的时候,对旧代码的改动可能会引入一些意想不到的问题

所以,当工厂负责创建对象比较少,并且这个产品对象比较固定时,推荐使用

怎么写

这里我主要使用 《大话设计模式》 的例子,将其改成 C++ 版本, 就不单独举例子了

实现一个加减乘除功能,要求输入2个数和运算符,得到结果

运算符对象代码如下

class Operation
{
public:
    Operation():A(0), B(0){}
    virtual ~Operation(){}

    double GetA() const { return A; }
    double GetB() const { return B; }
    void SetA(double x) { A=x; }
    void SetB(double y) { B=y; }
    double virtual GetResult(){ return 0; }

private:
    double A, B;
};

class Add : public Operation
{
public:
    double GetResult()
    {
        return GetA()+GetB();
    }
};

class Sub : public Operation
{
public:
    double GetResult()
    {
        return GetA()-GetB();
    }
};

class Mul : public Operation
{
public:
    double GetResult()
    {
        return GetA()*GetB();
    }
};

class Div : public Operation
{
public:
    double GetResult()
    {
        if (GetB() == 0)
            throw string("Division by zero condition!");
        return GetA()/GetB();
    }
};

运算符工厂类实现如下:

enum OperatorType
{
    ADD = 0,
    SUB,
    MUL,
    DIV
};

class SimpleFactory
{
public:
    static Operation * CreateOperator(OperatorType type)
    {
        Operation * p;
        switch(type)
        {
        case ADD:
            p = new Add();
            break;
        case SUB:
            p = new Sub();
            break;
        case MUL:
            p = new Mul();
            break;
        case DIV:
            p = new Div();
            break;
        }
        return p;
    }
};

main 调用方式如下:

int main()
{
    double A = 20;
    double B = 10;

    Operation *op = SimpleFactory::CreateOperator(OperatorType::SUB);
    op->SetA(A);
    op->SetB(B);
    try {
        cout<< op->GetResult() <<endl;
    } catch (string exception ) {
        cout<< exception <<endl;
    }

    delete op;
    op = nullptr;
}

简单总结

简单工厂模式确定对得起这个名字,确实足够简单

只有 一个 工厂,这个工厂的实例,维护了旗下所有具有共同属性的产品的创建逻辑

所以当需要扩展产品的时候,就只能修改这个工厂,从而违反了 开放-封闭原则 (软件实体(类、模块、函数)可以扩展,但是不可修改的)

而接下来的工厂方法模式,会在一定程度上解决这个问题