大话设计模式

  1. 简单工厂模式
  2. 策略模式(Stretagy)
  3. 单一职责原则(SRP)
  4. 开放封闭原则
  5. 依赖倒转原则

简单工厂模式

这个模式与面向对象相关,通过面向对象的三大特征来使得程序达到可复用,易修改,易扩展的效果

本模式以写一个计算器功能,要求根据用户的输入输出相应的结果
如果没有使用任何模式代码可能如下

int main()
{
    try{
        std::cout<<"请输入数字A:\n";
        double a;
        std::cin>>a;
        std::cout<<"请输入运算符号+,-,*,/:\n";
        char opt;
        std::cin>>opt;
        //下面再类似地读入B
        switch(opt)
        {
            case '*':
            //操作
            break;
            case '/':
            //操作,注意除法需要自己判断除数是否为0,try catch不捕捉除零错误
            break;
            //类似的
        }
    }catch(...){
        std::cout<<"您的输入有误\n";
    }
    return 0;
}

上面的代码想要复用就必须拷贝粘贴代码,如果有多个地方要使用那多个地方就会出现重复的代码,这是在编码时应该避免的。下面通过面向的封装特性将该功能进行封装,使得其复用性大大提高

class Operation{
    public:
    static double GetResult(double numA,double numB,string operate){
        double result = 0;
        switch(operate){
            case:
            //实现相应功能
        }
        return result;
    }
};

将计算这个功能给封装起来,数据的读入和检查由客户完成,这样这个代码的复用性就大大提高了,不单是现在这个程序可以用它,只要是需要通过输入得到结果的地方都可以使用

但是如果此时想要给这个功能添加一些新的计算如开根求幂等,就需要去修改switch case的结构,一方面需要将所有运算的源码交给修改人员,这不安全可能会破坏其它的运算,另一方面这样的修改会使得原来已有的运算重新编译,这是不合理的.说白了这里需要解开各个运算之间的编译耦合
下面是利用继承的方式修改的代码

class Operation{
    protected:
    double numA_;
    double numB_;
    public:
    void SetA(double val);
    double GetA()const;
    //numB_类似有get与set
    virtual double GetResult(){
        double ans=0;
        return ans;
    }
};
class OperationAdd:public Operation{
    public:
    virtual double GetResult(){
        return numA_ + numB_;
    }   
};

class OperationDiv:public Operation{
    public:
    virtual double GetResult()override {
        if(numB_ == 0 )
            throw Error;
        return numA_ / numB_;
    }
};
//原先其它运算符类似
class OperationSqrt:public Opearation{
    if (numA_ <0)
        throw Error;
    return sqrt(numA_);
};

这样既增加了安全性又提高了扩展性,现在的问题就是客户必须要知道自己的运算需要调用什么样的类,但如果程序很大,对客户来说去众多类里面找到自己想要的类是很不方便的,利用多态的性质将这个任务交给一个特定的类去完成,这个类即工厂

class OperationFactory{
    public:
    static Operation* createOperate(char operate){
        Operation* opt = nullptr;
        switch(operate){
            case '*':
            opt = new OperationMul();
            break;
            case '+':
            opt = new OperationAdd();
            break;
            //...
        }
        return opt;
    }
};
//客户端的代码
Operation *opt;
opt = OperationFactory::createOperate('+');
opt->setA(10);
opt->setB(20);
double result = opt->GetResult();

策略模式(Stretagy)

单一职责原则(SRP)

如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会影响到其它职责的实现,这种耦合会导致脆弱的设计

开放封闭原则

对修改关闭,对扩展开放

依赖倒转原则

抽象不应该依赖底层模块,两个都应该依赖抽象。抽象不应该依赖细节,细节应该依赖于抽象。
简单地说就是应该针对接口编程而不是针对实现编程

假设在做一个大项目时需要访问数据库,常用代码会写成函数库,在上层模块中调用这些函数即可,这里就是上层模块对底层模块的依赖。但如果上层的逻辑没有变化但需要换掉访问的数据库,那就出现问题了,因为上层模块与底层是绑在一起的。

再举一个例子就是主机,CPU,内存,硬盘都是根据接口标准制造的,如果说它们根据主板实现那主板一坏其它部件都不能使用了
@startuml
(登录论坛)
(发帖子) as (tiezi_add)
usecase 删帖子 as tiezi_del
@enduml


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2128099421@qq.com

×

喜欢就点赞,疼爱就打赏