设计模式之工厂模式(1):概念简单工厂模式,工厂方法模式

1 简单工厂模式

  • 引入

函数输入的变量,其类型和名称相同,但是具体传入值不同,
由于某些变量值的不同,引起其执行过程不同,
其返回值类型和名称也相同。
——函数头相同,函数体不同,这为函数重写提供了条件(多态)

  • 简单示例场景

比如实现计算器的加减乘除时,无论是哪种运算,都需要两个数和一个运算符。

  • 代码

版本一:参数输入与功能定义放在一起

#include <stdio.h>

int main()
{
    double a,b;
    char operate;
    scanf("%lf %c %lf",&a,&operate,&b);
    double result=0;
    switch(operate)
    {
        case '+':result=a+b;break;
        case '-':result=a-b;break;
        case '*':result=a*b;break;
        case '/':result=a/b;break;
        defalut:
            return 0;
    }
    printf("%lf",result);
    return 0;
}

该方法将控制台输入和功能定义耦合在一起,当进行功能扩展——如增加一个取模运算,或者进行跨平台开发,比如不用cmd输入了,要开发一个Android的版本,那此时直接在原有代码上改动也罢,将逻辑供暖复制到其他平台也罢,都可能因为修改或者直接复制原有代码产生新的bug.


版本二:将计算功能与输入控制分离

#include <iostream>

using namespace std;

class Operation
{
    public:
    Operation(double operandA,double operandB,char operate)
    {
        this->operandA=operandA;
        this->operandB=operandB;
        this->operate=operate;
    }
    private:
        double operandA;
        double operandB;
        char operate;

    public:
        void setOperandA(double operandA)
        {
            this->operandA=operandA;
        }
        void setOperandB(double operandB)
        {
            this->operandB=operandB;
        }
        double getOperandA()
        {
            return this->operandA;
        }
        double getOperandB()
        {
            return this->operandB;
        }
        double getResult()
        {
            double result=0;
            switch(operate)
            {
                case '+':result=operandA+operandB;break;
                case '-':result=operandA-operandB;break;
                case '*':result=operandA*operandB;break;
                case '/':result=operandA/operandB;break;
                defalut:
                    return 0;
            }
            return result;
        }
};

int main()
{
    double oprA,oprB;
    double result;
    char opt;
    cin>>oprA>>oprB>>opt;
    Operation op(oprA,oprB,opt);
    result=op.getResult();
    cout<<result;
    return 0;
}

该版本代码将计算功能单独封装为类,两个运算数和一个运算符分别作为该操作类的私有属性,具体的计算功能是通过该类对外提供的getResult()方法进行的。

这样一来,在主程序调用运算功能时,无需知道运算细节;体现了面向对象的封装性。
此外,功能实现与调用相分离,降低了运算和调用的耦合,若跨平台使用,则仅需复制运算功能类即可,使得代码具有一定的可复用性。

但是,如果还需增加其他运算功能,如取模运算,仍需在运算类的switch中进行代码修改,在取模运算逻辑代码增加的同时,开发者能接触到加减乘除的代码,有机会对已有的加减乘除操作进行修改,从而产生bug甚至其他不安全因素。


版本三:分别对加,减,乘,除 进行类的定义,再定义一个工厂类对功能进行选择,调用类对输入进行控制

#include <iostream>
#include <cmath>
using namespace std;

class Operation
{
    public:
    Operation(double operandA,double operandB,char operate)
    {
        this->operandA=operandA;
        this->operandB=operandB;
        this->operate=operate;
    }
    protected:
        double operandA;
        double operandB;
        char operate;

    public:
        void setOperandA(double operandA)
        {
            this->operandA=operandA;
        }
        void setOperandB(double operandB)
        {
            this->operandB=operandB;
        }
        void setOperate(char operate)
        {
            this->operate=operate;
        }
        double getOperandA()
        {
            return this->operandA;
        }
        double getOperandB()
        {
            return this->operandB;
        }
        char getOperate()
        {
            return this->operate;
        }
        virtual double getResult()=0;
};
class AddOperation:public Operation
{
    public:
    AddOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
    double getResult()
    {
        return operandA+operandB;
    }
};

class MinusOperation:public Operation
{
    public:
    MinusOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
    double getResult()
    {
        return operandA-operandB;
    }
};
class MultipleOperation:public Operation
{
    public:
    MultipleOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
    double getResult()
    {
        return operandA*operandB;
    }
};
class DivOperation:public Operation
{
    public:
    DivOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){
    }
    double getResult()
    {
  //     cout<<operandB<<endl;
        if(fabs(this->operandB)>1e-2)
        {
            return this->operandA/this->operandB;
        }
    /   return -1;
//        else
//        {
            cout<<this->operandB<<endl;
//
//            cerr<<"wrong"<<endl;
//            return -1;
//        }
    }
};
class OperationFactory
{
    public :
        Operation *operation=NULL;
    public:
        Operation* createOperation(double operandA,double operandB,char opt)
        {
            switch(opt)
            {
                case '+':
                    {
                        AddOperation add(operandA,operandB,opt);
                        operation=&add;
                    }
                    break;
                case '-':
                    {
                        MinusOperation minus(operandA,operandB,opt);
                        operation=&minus;
                    }
                    break;
                case '*':
                    {
                        MultipleOperation multiple(operandA,operandB,opt);
                        operation=&multiple;
                    }
                    break;
                case '/':
                    {
                        DivOperation div(operandA,operandB,opt);
                        operation=&div;
                    }
                    break;
                default:
                    break;
            }
            return operation;
        }
};
int main()
{
    double oprA,oprB;
    double result;
    char opt;
    cin>>oprA>>oprB>>opt;

    OperationFactory factory;
    Operation *option=factory.createOperation(oprA,oprB,opt);
    result=option->getResult();
    cout<<result;
    return 0;
}


/*
Operation op;
报错信息二cannot declare field "xxx" to be of abstract type"xxx"
报错原因:把c++抽象类(含纯虚函数的类叫抽象类)当做成员对象,因为抽象类不可实例化,解决方法把实例对象改成指针

case '+':AddOperation add(operandA,operandB,operate);operation=&add;break;
https://blog.csdn.net/zzwdkxx/article/details/27561393

在case '+' 中定义的add对象在其他cae中仍然有效
*/

  • 优缺点

优点:
将各个功能操作——加减乘除——各自被封装为一类,因输入输出类型相同,故都继承自同一父类。在进行功能扩展添加时,无需在原有的功能类中进行修改,而是新定义一个功能类。扩展性较好。
将产品定义,产品生产,产品调用的三部分代码相分离。对产品生产者隐藏了产品定义细节,对产品使用者隐藏了产品生产的细节。
缺点:
此外,在添加功能时,需要对选择要生产何种产品的工厂类添加分支,对于工厂类而言,不满足“开放-封闭”原则。

  • UML图

在这里插入图片描述

2 工厂方法模式

  • 引入

简单工厂模式,在新增功能时,需对已有的工厂类代码中的选择产品进行分支的添加,不满足对修改封闭的原则。

  • 简单示例场景

仍然是简单的计算器加减乘除。

  • 代码

#include <iostream>
#include <cmath>
using namespace std;

class Operation
{
    public:
    Operation(double operandA,double operandB,char operate)
    {
        this->operandA=operandA;
        this->operandB=operandB;
        this->operate=operate;
    }
    protected:
        double operandA;
        double operandB;
        char operate;

    public:
        void setOperandA(double operandA)
        {
            this->operandA=operandA;
        }
        void setOperandB(double operandB)
        {
            this->operandB=operandB;
        }
        void setOperate(char operate)
        {
            this->operate=operate;
        }
        double getOperandA()
        {
            return this->operandA;
        }
        double getOperandB()
        {
            return this->operandB;
        }
        char getOperate()
        {
            return this->operate;
        }
        virtual double getResult()=0;
};
class AddOperation:public Operation
{
    public:
    AddOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
    double getResult()
    {
        return operandA+operandB;
    }
};

class MinusOperation:public Operation
{
    public:
    MinusOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
    double getResult()
    {
        return operandA-operandB;
    }
};
class MultipleOperation:public Operation
{
    public:
    MultipleOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
    double getResult()
    {
        return operandA*operandB;
    }
};
class DivOperation:public Operation
{
    public:
    DivOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){
    }
    double getResult()
    {
  //     cout<<operandB<<endl;
        if(fabs(this->operandB)>1e-2)
        {
            return this->operandA/this->operandB;
        }
      return -1;
//        else
//        {
            cout<<this->operandB<<endl;
//
//            cerr<<"wrong"<<endl;
//            return -1;
//        }
    }
};

class InterfaceOperationFactory
{
    public:
        Operation *op=NULL;
    virtual Operation *createOperation(double operandA,double operandB,char opt )=0;
};

class AddOperationFactory:public InterfaceOperationFactory
{
    public:

    Operation *createOperation(double operandA,double operandB,char opt )
    {
        AddOperation add(operandA,operandB,opt );
        op=&add;
        return op;
    }
};
class MinusOperationFactory :public InterfaceOperationFactory
{
    public:
    Operation *createOperation(double operandA,double operandB,char opt )
    {
         MinusOperation minus(operandA,operandB,opt );
        op=&minus;
        return op;
    }
};
class MultipleOperationFactory:public InterfaceOperationFactory
{
    public:
    Operation *createOperation(double operandA,double operandB,char opt )
    {
        MultipleOperation multiple(operandA,operandB,opt );
        op=&multiple;
        return op;
    }
};
class DivOperationFactory:public InterfaceOperationFactory
{
    public:
    Operation *createOperation(double operandA,double operandB,char opt )
    {
        DivOperation div(operandA,operandB,opt );
        op=&div;
        return op;
    }
};
int main()
{
    double oprA,oprB;
    double result;
    char opt;
    cin>>oprA>>oprB>>opt;

    //定义抽象工厂和子类工厂,让抽象工厂引用指向子类工厂对象
    InterfaceOperationFactory *factory;
    DivOperationFactory addFactory;
    factory=&addFactory;
    //使用工厂的多态生产 产品
    Operation *operation=factory->createOperation(oprA,oprB,opt);
    //使用产品的多态输出产品结果
    cout<<operation->getResult();
    return 0;
}
  • UML图

-在这里插入图片描述

  • 优缺点

优点:将对工厂的修改封闭起来,在工厂类部分满足了开放-封闭原则。若要进行计算器的功能添加,只要分别继承运算类,工厂类。调用时需要修改实际操作对应的子工厂类,将修改从产品生产模块移到了产品调用模块。
缺点:每新增一个产品,需要创建一个对应的工厂类,增加代码量。

参考文献
《大话设计模式》 程杰

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值