【设计模式】工厂方法模式

简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。工厂方法模式的UML图如下:


例如在简单工厂模式中出现的工厂函数:

Operation* FactoryFunction(double left, double right, char op)
{
    switch (op)
    {
    case '+':
        return new Add(left, right);
        break;
    case '-':
        return new Sub(left, right);
        break;
    case '*':
        return new Mul(left, right);
        break;
    case '/':
        return new Div(left, right);
        break;
    default:
        throw runtime_error("Operation invalid!");
        break;
    }
}

用户选择一个需要的运算符并传给工厂函数,工厂函数根据选择实例化一个对应的运算符并返回给客户程序。这里的好处是将细节处理都交给了工厂函数,这些操作对用户程序员来说是透明的。但是也有缺点:当我们需要添加新的运算操作时,都需要在工厂函数内添加case分支语句,这违反了开放封闭原则。 开放封闭原则是指软件实体应该可以扩展,但是不可修改 。为了不违反开放封闭原则,可以使用工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。下面是用C++编写的运用了工厂方法模式的计算器类。

#include <iostream>
 
using namespace std;
 
// 运算基类
class Operation {
public:
    Operation(const double left, const double right)
    {
        lhs = left;
        rhs = right;
    }
 
    virtual double Calculate() = 0; // 纯虚函数
 
protected:
    double lhs;
    double rhs;
};
 
// 加法运算
class Add : public Operation {
public:
    Add(double left, double right) : Operation(left, right)
    {}
 
    double Calculate()
    {
        return lhs + rhs;
    }
};
 
// 减法运算
class Sub : public Operation {
public:
    Sub(double left, double right) : Operation(left, right)
    {}
 
    double Calculate()
    {
        return lhs - rhs;
    }
};
 
// 乘法运算
class Mul : public Operation {
public:
    Mul(double left, double right) : Operation(left, right)
    {}
 
    double Calculate()
    {
        return lhs * rhs;
    }
};
 
// 除法运算
class Div : public Operation {
public:
    Div(double left, double right) : Operation(left, right)
    {
        try
        {
            if (right == 0)
                throw runtime_error("The divisor cannot be 0\n");
 
        }
        catch (const runtime_error &e)
        {
            cout << e.what() << endl;
            throw;
        }
    }
 
    double Calculate()
    {
        return lhs / rhs;
    }
};
 
// 抽象工厂
class AbstractFactory {
public:
    virtual Operation* CreateOperation(const int left, const int right) = 0;
};
 
// 根据运算实现出各自的工厂类
class AddFactory : public AbstractFactory {
public:
    Operation* CreateOperation(const int left, const int right)
    {
        return new Add(left, right);
    }
};
 
class SubFactory : public AbstractFactory {
public:
    Operation* CreateOperation(const int left, const int right)
    {
        return new Sub(left, right);
    }
};
 
class MulFactory : public AbstractFactory {
public:
    Operation* CreateOperation(const int left, const int right)
    {
        return new Mul(left, right);
    }
};
 
class DivFactory : public AbstractFactory {
public:
    Operation* CreateOperation(const int left, const int right)
    {
        return new Div(left, right);
    }
};
 
int main()
{
    AbstractFactory *creator = new AddFactory();
    Operation *add = creator->CreateOperation(11, 22);
    cout << add->Calculate() << endl;
    delete creator;
 
    creator = new SubFactory();
    Operation *sub = creator->CreateOperation(25, 32);
    cout << sub->Calculate() << endl;
    delete creator;
 
    creator = new MulFactory();
    Operation *mul = creator->CreateOperation(11, 11);
    cout << mul->Calculate() << endl;
    delete creator;
 
    creator = new DivFactory();
    Operation *div = creator->CreateOperation(50, 8);
    cout << div->Calculate() << endl;
    delete creator;
 
    // 别忘记销毁指针
    delete add;
    delete sub;
    delete mul;
    delete div;
 
    system("pause");
    return 0;
}

运行结果:


上面的例子中,定义了一个AbstractFactory抽象工厂类,创建实际对象的工厂类都要继承这个抽象基类并重写具体产生对象的方法CreateOperation。当添加新的运算操作时,不需要修改原有的工厂类,只需要继承AbstractFactory定义一个新的工厂类即可,这就符合了封闭开放原则。

参考:

《大话设计模式》第8章

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值