c++—设计模式

1. 设计模式概述

        (1)目标:面向对象系统的分析和设计实际上追求的就是两点:高内聚和低耦合

        (2)核心思想:隔离变化,封装变化;把变化的抽象为不变的,并且封装起来,提供不变的接口;

        (3)设计模式的地位:设计模式在面向对象中的作用,就相当于数据结构在面向过程中的作用一样;本质是一套千人总结的代码可重复性高的几套程序整体架构;

        (4)设计模式的分类

创建型,隐藏创建对象的方式(让用户不知道创建的具体类型对象),主要是用函数封装变化的输入,尤其是new的解耦(不在主函数里面new对象,而是用类封装起来,降低与类型名之间的耦合度)工厂方法模式factory,定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中
抽象工厂模式abstract,提供一个创建一系列相关或者相互依赖的接口,而无需指定它们具体的类
单例模式singleton,保证一个类仅有一个实例,并提供一个访问它的全局访问点
结构型,利用组合的方式将抽象的类组合起来,重在依赖于抽象类,重在类代理模式proxy,为其他对象提供一种代理以控制对这个对象的访问
适配器模式adapter,是将一个类的接口转换成客户希望的另外的一个接口,使得原来由于接口不兼容而不能一起工作的那些类可以一起工作
组合模式是将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性;组合的优势高于继承,因为耦合度低
外观模式是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
行为型,将变化的成员函数进行抽象,依赖于抽象,重在方法模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

        (5)设计模式的六大原则(重点)

        ①开放封闭原则:当需要新增功能时,只增加新的类(新的代码),不修改原来的类,不修改源代码;因为修改源代码会导致问题无法定位;

        ②依赖倒转原则:对于类中的成员函数方法,要依赖于不变的抽象(抽象类的统一接口),而不是依赖于具体的实现类,具体怎么变交给具体类;

        ③接口隔离原则:类之间的依赖关系应该建立在最小的接口上,就是说接口的参数个数要少,内聚性高,这样系统越灵活;如果参数个数过多,则开发难度增加,可维护性降低;

        ④里氏替换原则:任何基类都可以出现的地方,子类一定可以出现,实现多态;主要是采用继承的方式,继承方式的优点(提高代码的复用性,与可扩展性),缺点(继承是侵入式的,只要继承就拥有了父类的属性和方法,降低了代码的灵活性;增强了耦合性,当基类的属性或方法改变时,必须考虑子类的修改,可能会有大段代码需要重构);补充的四层含义:

        ❶派生类必须实现基类的抽象方法,否则派生类也无法实例化对象;但是一般不覆写基类的非抽象(已实现)的方法;

        ❷派生类可增加自己特有的函数方法

        ❸当派生类覆写基类的函数方法时,函数的输入参数应该更加宽松;

        ❹当派生类的方法实现基类的抽象函数方法时,函数的返回值应该比基类更加严格;

        总结:将子类定义为抽象类,并定义抽象的成员函数方法,派生类继承后,让派生类重新定义这些方法;此时基类是抽象类,也不可以实例化对象;

        ⑤合成复用原则:尽量使用组合的方式实现复用(因为继承导致耦合度提高),就是在自己的类里面定义其他类的属性或者在自己的成员函数中的参数是其他类的对象或指针(这就是两种实现组合的方式),这样就可以该成员属性调用其他类的成员函数方法;引申出来为类与类之间的关系:

类与类之间的关系
泛化继承关系即派生类与基类之间的关系,基类的属性与方法,派生类都有,且派生类还可以有额外的属性与方法
实现关系B类中的函数的形参是A类的成员或指针
依赖关系B类中的函数的形参是A类的成员或指针、B类的成员函数中的局部变量是A类的对象或指针
关联关系
聚合关系
组合关系B类中的成员属性是A类的对象或对象指针;可以使系统更加灵活,降低类与类之间的耦合度

        ⑥迪米特法则:就是A类不直接链接C类,而是通过B类中转;

2. 设计模式的具体实现,以计算器(四则运算的例子:加减乘除)来演示:

各版本之间的关系:版本1和版本3相对独立;

以版本2为基础,版本4/5/6/7/8/9均是在其上面修改,其中版本9是直接在版本2上增加的代理类;

版本一:

        思路是定义一个完整的类,里面含有计算的数值与计算的方法,数值通过构造函数的方式传进来,方法通过该类的对象进行调用,并将加减乘除的符号传给该函数的参数;

        耦合度:很高,因为比如说新增计算%取余运算时,需要破坏原有的类;

        优点:实现简单;

        缺点:耦合度较高,程序扩展型差;

#include <iostream>
#include <string>

using namespace std;

class Cal
{
public:
    Cal(int a, int b) : m_a(a),m_b(b)
    {
    }

    double get_result(string &op)
    {
        if(op == "+")
        {
            return m_a + m_b;
        }
        else if(op == "-")
        {
            return m_a - m_b;
        }
        else if(op == "*")
        {
            return m_a * m_b;
        }
        else if(op == "/")
        {
            return m_a / m_b;
        }
        else if(op == "%")  //这里新增就需要破坏这个类
        {
            return double((int)m_a % (int)m_b);
        }
        return 0;
    }

private:
    double m_a;
    double m_b;
};

int main(int argc, char **argv)
{
    double a = 0;
    double b = 0;
    string op{};

    cout<<"please input the a : ";
    cin>>a;
    cout<<"please input the b : ";
    cin>>b;
    cout<<"please input the op : ";
    cin>>op;

    Cal cal(a,b);
    cout<<"result = "<<cal.get_result(op)<<endl;

    return 0;
}

版本二:

        思路:通过一个共同的抽象类(基类),提供构造函数(给计算值a,b赋值),提供统一的计算函数方法(接口),该函数是纯虚函数,具体的实现由各派生类实现;实现方式是通过基类的指针调用各派生类的计算方法;

        耦合度:低,当新增功能时,只需要新增一个类去继承基类,然后修改具体的计算实现方式;例如新增一个Mod类实现取余计算的方法;

        优先:耦合度低,扩展性强;

        缺点:new暴露在主函数中,对用户可见,且与类名之间的耦合度高,没有解耦;

#include <iostream>
#include <string>

using namespace std;

class Cal  //抽象的基类的作用一:通过构造函数给a,b赋值;作用二:提供统一的函数方法接口,计算结果;
{          //具体的实现交给派生类;通过该抽象类指针调用各派生类的函数实现方法;
public:
    Cal(int a, int b) : m_a(a),m_b(b)
    {
    }

    virtual ~Cal()
    {
    }

    virtual double get_result() = 0;

// private:  //因为派生类要在自己的类内访问,所以不能够设置为私有属性;
    double m_a;
    double m_b;
};

class Add : public Cal
{
public: 
    Add(int a, int b) : Cal(a,b) //给计算数值赋值也是由派生类完成,调用基类的构造函数,给a,b赋值;
    {
    }

    double get_result()
    {
        return m_a + m_b;
    }

    ~Add() = default;
};

class Sub : public Cal
{
public: 
    Sub(int a, int b) : Cal(a,b)
    {
    }

    double get_result()
    {
        return m_a + m_b;
    }

    ~Sub() = default;
};

class Mul : public Cal
{
public: 
    Mul(int a, int b) : Cal(a,b)
    {
    }

    double get_result()
    {
        return m_a * m_b;
    }

    ~Mul() = default;
};

class Div : public Cal
{
public: 
    Div(int a, int b) : Cal(a,b)
    {
    }

    double get_result()
    {
        return m_a / m_b;
    }

    ~Div() = default;
};

class Mod : public Cal
{
public: 
    Mod(int a, int b) : Cal(a,b)
    {
    }

    double get_result()
    {
        return double((int)m_a % (int)m_b);
    }

    ~Mod() = default;
};

int main(int argc, char **argv)
{
    double a = 0;
    double b = 0;
    string op{};

    cout<<"please input the a : ";
    cin>>a;
    cout<<"please input the b : ";
    cin>>b;
    cout<<"please input the op : ";
    cin>>op;

    Cal *cal;

    if(op == "+")
    {
        cal = new Add(a,b);
    }
    else if(op == "-")
    {
        cal = new Sub(a,b);
    }
    else if(op == "*")
    {
        cal = new Mul(a,b);
    }
    else if(op == "/")
    {
        cal = new Div(a,b);
    }
    else if(op == "%")
    {
        cal = new Mod(a,b);
    }

    cout<<"result = "<<cal->get_result()<<endl;

    return 0;
}

版本三:

        思路:先有一个抽象的函数方法基类,然后加减乘除继承该基类,并在派生类中覆写该函数方法,函数接口是接收要计算的a,b的值,并不作为成员属性存储;然后利用一个组合类,将上面所有的基类的指针当做属性成员进行存储,同样的并不存储a,b;内部的成员函数的方法接受a,b和op,再根据op进行选择对应的成员指针指向的函数方法(上面的各基类);

        耦合度:低,只需要新增一个类继承抽象的函数方法基类,然后组合类中新增对应的派生类指针成员即可;

        优点:耦合度低,扩展性好;

        缺点:暂无

#include <iostream>
#include <string>

using namespace std;

class Operation  //这个是一个抽象类(对函数方法的抽象),并不负责对a,b的赋值;
{                //各派生类主要负责对该方法的覆写;
public:
    virtual double get_result(double a, double b) = 0;
};

class AddOperation : public Operation  //覆写了基类中的函数方法,a,b由调用该类中的函数方法时传递进来;
{
public:
    double get_result(double a, double b)
    {
        return a + b;
    }
};

class SubOperation : public Operation
{
public:
    double get_result(double a, double b)
    {
        return a -+ b;
    }
};

class MulOperation : public Operation
{
public:
    double get_result(double a, double b)
    {
        return a * b;
    }
};

class DivOperation : public Operation
{
public:
    double get_result(double a, double b)
    {
        return a / b;
    }
};

class ModOperation : public Operation
{
public:
    double get_result(double a, double b)
    {
        return double((int)a % (int)b);
    }
};

class Cal  //这是一个组合的类,将上面覆写函数方法的派生类指针组合到该类里面,作为函数成员属性;
{          //这写派生类的指针作为属性成员,当然由构造函数进行初始化,由主函数调用时传进来;
public:    //这里两种构造函数对应两种初始化方法,private四个成员的两种初始化方法,现在这种方式就无需主函数传进来了;
    // Cal(Operation *add, Operation *sub, Operation *mul, Operation *div, Operation *mod) : m_add(add),m_sub(sub),m_mul(mul),m_div(div),m_mod(mod)
    // {
    // }

    Cal()
    {
    }
    
    double get_result(double a, double b, string &op)  //该组合类的函数方法,参数负责接收a,b和op,由调用该函数方法时传进来;
    {
        if(op == "+")
        {
            return m_add->get_result(a,b);
        }
        else if(op == "-")
        {
            return m_sub->get_result(a,b);
        }
        else if(op == "*")
        {
            return m_mul->get_result(a,b);
        }
        else if(op == "/")
        {
            return m_div->get_result(a,b);
        }
        else if(op == "%")
        {
            return m_mod->get_result(a,b);
        }
        return 0;
    }

private:
    // Operation *m_add;
    // Operation *m_sub;
    // Operation *m_mul;
    // Operation *m_div;
    // Operation *m_mod;

    Operation *m_add = new AddOperation;
    Operation *m_sub = new SubOperation;
    Operation *m_mul = new MulOperation;
    Operation *m_div = new DivOperation;
    Operation *m_mod = new ModOperation;
};

int main(int argc, char **argv)
{
    double a = 0;
    double b = 0;
    string op{};

    cout<<"please input the a : ";
    cin>>a;
    cout<<"please input the b : ";
    cin>>b;
    cout<<"please input the op : ";
    cin>>op;

    // Cal cal(new AddOperation, new SubOperation, new MulOperation, new DivOperation, new ModOperation);
    Cal cal;
    cout<<"result = "<<cal.get_result(a,b,op)<<endl;

    return 0;
}

版本四:

        思路:主要是对版本2中new的高耦合度进行优化,将其封装成类;这个封装new的Factory类,就相当于是一个工厂,根据传进来的op选择生成对应的派生类指针,既而可以在主函数中调用派生类方法;

        耦合性:耦合度低,新增功能时,新增一个类继承Cal,然后在工厂Factory类中增加elseif即可;

        优点:耦合度低,扩展性强;

        缺点:a,b是不变的,而op是变化的,没有分隔开;

#include <iostream>
#include <string>

using namespace std;

class Cal  //该版本是2版本的优化,主要优化在将new进行封装在Factory类中,避免在主函数中出现;
{
public:
    Cal(double a, double b) : m_a(a),m_b(b)
    {
    }

    virtual double get_result() = 0;
    
    virtual ~Cal()
    {   
    }

    double m_a;
    double m_b;
};

class Add : public Cal
{
public:
    Add(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a + m_b;
    }    
};

class Sub : public Cal
{
public:
    Sub(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a - m_b;
    }    
};

class Mul : public Cal
{
public:
    Mul(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a * m_b;
    }    
};

class Div : public Cal
{
public:
    Div(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a / m_b;
    }    
};

class Mod : public Cal
{
public:
    Mod(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return double((int)m_a % (int)m_b);
    }    
};

class Factory
{
public:
    Factory() = default;
    static Cal * createfactory(double a, double b, string &op)
    {
        if(op == "+")
        {
            return new Add(a,b);  //这里根据op的不同,返回不同的派生类指针,从而在主函数中可以调用派生类方法;
        }
        else if(op == "-")
        {
            return new Sub(a,b);
        }
        else if(op == "*")
        {
            return new Mul(a,b);
        }
        else if(op == "/")
        {
            return new Div(a,b);
        }
        else if(op == "%")
        {
            return new Mod(a,b);
        }
        return 0;
    }
};

int main(int argc, char **argv)
{
    double a = 0;
    double b = 0;
    string op{};

    cout<<"please input the a : ";
    cin>>a;
    cout<<"please input the b : ";
    cin>>b;
    cout<<"please input the op : ";
    cin>>op;

    Cal * cal;
    cal = Factory::createfactory(a,b,op);
    cout<<"result = "<<cal->get_result()<<endl;

    return 0;
}

版本五:

        思路:①先定义一个抽象的基类(提供a,b,以及一个纯虚函数方法),相当于生产线模板;②增加5个派生类,继承上面的抽象类,实现不同的函数方法,相当于具体的生产线;③再定义一个基类,相当于车间模板,用来生产不同的生产线指针;④增加5个派生类,相当于具体的车架,由不同的生产线;⑤最后再定义一个基类,相当于一个工厂,根据op的不同生产选择不同的车间;

        耦合度:低,在版本四的基础上将a,b与变化的op分隔开,将op进行封装;

        优点:耦合度低,扩展性强;

        缺点:暂无;

#include <iostream>
#include <string>

using namespace std;

class Cal  //在版本4的基础上,将a,b和op分开,因为变化的是op,a和b不变化;
{
public:
    Cal(double a, double b) : m_a(a),m_b(b)
    {
    }
    virtual double get_result() = 0;

    double m_a;
    double m_b;
};

class Add : public Cal
{
public:
    Add(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a + m_b;
    }
};

class Sub : public Cal
{
public:
    Sub(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a - m_b;
    }
};

class Mul : public Cal
{
public:
    Mul(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a * m_b;
    }
};

class Div : public Cal
{
public:
    Div(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return m_a / m_b;
    }
};

class Mod : public Cal
{
public:
    Mod(double a, double b) : Cal(a,b)
    {
    }
    double get_result()
    {
        return double((int)m_a % (int)m_b);
    }
};

class CalFactory  //这里是主要的变化点,这是一个抽象类,用于产生Cal*指针,来调用上面的多态实现方法;
{                 //这里相当于一个工厂里的车间模板,可以指向不同的生产线(cal*指针);
public:
    CalFactory() = default;
    virtual Cal * createoperator(double a, double b) = 0;
};

class AddFactory : public CalFactory  //继承上面的车间模板,生产不同的生产线指向(cal*指针);
{
public:
    Cal * createoperator(double a, double b)
    {
        return new Add(a,b);
    }
};

class SubFactory : public CalFactory
{
public:
    Cal * createoperator(double a, double b)
    {
        return new Sub(a,b);
    }
};

class MulFactory : public CalFactory
{
public:
    Cal * createoperator(double a, double b)
    {
        return new Mul(a,b);
    }
};

class DivFactory : public CalFactory
{
public:
    Cal * createoperator(double a, double b)
    {
        return new Div(a,b);
    }
};

class ModFactory : public CalFactory
{
public:
    Cal * createoperator(double a, double b)
    {
        return new Mod(a,b);
    }
};

class Factory  //这是一个整体工厂,用来生产不同的车间,即产出 CalFactory*
{              //这里将op与a,b分开,单独封装变化的op;
public:
    Factory() = default;
    
    static CalFactory * createFactory(string &op)
    {
        CalFactory * factory;

        if(op == "+")
        {
            factory = new AddFactory();
        }
        else if(op == "-")
        {
            factory = new SubFactory();
        }
        else if(op == "*")
        {
            factory = new MulFactory();
        }
        else if(op == "/")
        {
            factory = new DivFactory();
        }
        else if(op == "%")
        {
            factory = new ModFactory();
        }
        return factory;
    }
};

int main(int argc, char **argv)
{
    double a = 0;
    double b = 0;
    string op{};

    cout<<"please input the a : ";
    cin>>a;
    cout<<"please input the b : ";
    cin>>b;
    cout<<"please input the op : ";
    cin>>op;

    CalFactory * factory = Factory::createFactory(op);  //类的静态成员函数利用类名即可访问,不需要实例化对象;
    Cal *cal = factory->createoperator(a,b);
    cout<<"result = "<<cal->get_result()<<endl;

    return 0;
}

版本六:

        思路:在版本5的基础上优化,将最后的Factory舍弃,利用第三方容器去管理(内部是容器+map),需要的运算放入容器;需要用时,根据op在容器里查找,生成对应的车间指针,然后生成不同的生产线指针,既而可以调用不同的生产线,进行多态运算;

        耦合度:低,程序扩展性极好,提前将所有可能用到的运算放入第三方容器里面;

        优点:耦合度低,采用第三方容器管理多态运算,维护方便;

        缺点:暂无;

cpp:

#include <iostream>
#include <string>
#include <memory>
#include "IOC1.hpp"

using namespace std;
           //在版本5的基础上优化,将最后的Factory舍弃,利用第三方容器去管理(内部是容器+map),需要的运算放入容器;
           //需要用时,根据op在容器里查找,生成对应的车间指针,然后生成不同的生产线指针,既而可以调用不同的生产线,进行多态运算;
class Cal  //先有一个基类,加减乘除继承,实现具体方法
{
public:
    Cal(double a, double b) : m_a(a), m_b(b)
    {
    }
    virtual ~Cal()
    {
    }
    virtual double get_result() = 0;
    double m_a;
    double m_b;
};

class Add : public Cal
{
public:
    Add(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a + m_b;
    }
};

class Sub : public Cal
{
public:
    Sub(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a - m_b;
    }
};

class Mul : public Cal
{
public:
    Mul(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a * m_b;
    }
};

class Div : public Cal
{
public:
    Div(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a / m_b;
    }
};

class CalFactory  //这个计算工厂类,是为了将op这个变化点封装起来,下面继承的就相当于各个小车间,实现产生指针的加减乘除
{
public:
    virtual Cal *createOperator(double a, double b) = 0;
};

class AddFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Add(a,b);  //进行构造,并给m_a,m_b传值
    }
};

class SubFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Sub(a,b);
    }
};

class MulFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Mul(a,b);
    }
};

class DivFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Div(a,b);
    }
};

int main(int argc, char **argv)
{
    string op;
    double a;
    double b;

    cout<<"please input a : ";
    cin>>a;
    cout<<"please input b : ";
    cin>>b;
    cout<<"please input op : ";
    cin>>op;

    IocContainer<CalFactory>con;
    con.RegisterType<AddFactory>("+");
    con.RegisterType<SubFactory>("-");
    con.RegisterType<MulFactory>("*");
    con.RegisterType<DivFactory>("/");
    //["+",[](){return new AddFactory;}], ["-",[](){return new SubFactory;}]
    //["*",[](){return new MulFactory;}], ["/",[](){return new DivFactory;}]

    CalFactory *factory = con.Resolve(op);

    Cal *cal = factory->createOperator(a,b);
    cout<<"result = "<<cal->get_result()<<endl;

    return 0;
}

hpp:


#include <string>
#include <map>
#include <memory>
#include <functional>
#include <iostream>
using namespace std;

template <class T>
class IocContainer 
{
public:
	IocContainer(void){}
	~IocContainer()
	{

	}
	//注册需要创建对象的构造函数,通过一个唯一的标识,以便于以后查找
	template<class Drived>
	void RegisterType(string strKey) 
	{
		std::function<T* ()> function = [] {return new Drived();};
		RegisterType(strKey, function);
	}

	//根据唯一的标识(op)去查找对应的构造函数
	T* Resolve(string strKey) 
	{
		if (m_createMap.find(strKey) == m_createMap.end())
		{
			return nullptr;
		}
		std::function<T* ()> function = m_createMap[strKey];
		return function();
	}

	//创建智能指针
	std::shared_ptr<T> ResolveShared(string strKey) 
	{
		T* ptr = Resolve(strKey);
		return std::shared_ptr<T>(ptr);
	}
private:
	void RegisterType(string strKey, std::function<T* ()> creator) 
	{
		if (m_createMap.find(strKey) != m_createMap.end()) 
		{
			throw std::invalid_argument("已经存在这个key了");
		}
		m_createMap.emplace(strKey, creator);
	}

private:
	map<string, std::function<T* ()>> m_createMap;
};

版本七:

        思路:本版本较版本6新增了一个类,然后全面增加了关于类的加减乘除,构建了车间、生产线,同样采用的是第三方容器管理;hpp同版本6;

        耦合度:低,程序扩展性良好;

        优点:耦合度低,实现了自定义类的四则运算;

        缺点:暂无;

cpp如下:hpp同版本6

#include <iostream>
#include <string>
#include <memory>
#include "IOC1.hpp"

using namespace std;

class Cal  //先有一个基类,加减乘除继承,实现具体方法
{
public:
    Cal(double a, double b) : m_a(a), m_b(b)
    {
    }
    virtual ~Cal()
    {
    }
    virtual double get_result() = 0;
    double m_a;
    double m_b;
};

class Add : public Cal
{
public:
    Add(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a + m_b;
    }
};

class Sub : public Cal
{
public:
    Sub(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a - m_b;
    }
};

class Mul : public Cal
{
public:
    Mul(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a * m_b;
    }
};

class Div : public Cal
{
public:
    Div(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a / m_b;
    }
};

class Mod : public Cal
{
public:
    Mod(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return double((int)m_a % (int)m_b);
    }
};

class Test  //新增了一个类,并全面增加了关于自定义类的运算(车间、生产线);
{
public:
    Test() = default;
    Test(int t) : m_t(t)
    {
    }

    int m_t;
};

ostream & operator<<(ostream &out, const Test &t)
{
    out<<t.m_t;
    return out;
}

class CalTest
{
public:
    CalTest(Test a, Test b) : m_a(a),m_b(b)
    {
    }
    virtual Test get_result() = 0;
    
    Test m_a;
    Test m_b;
};

class AddTest : public CalTest
{
public:
    AddTest(Test a, Test b) : CalTest(a,b)
    {
    }
    virtual Test get_result()
    {
        return Test(m_a.m_t + m_b.m_t);
    }
};

class SubTest : public CalTest
{
public:
    SubTest(Test a, Test b) : CalTest(a,b)
    {
    }
    virtual Test get_result()
    {
        return Test(m_a.m_t - m_b.m_t);
    }
};

class MulTest : public CalTest
{
public:
    MulTest(Test a, Test b) : CalTest(a,b)
    {
    }
    virtual Test get_result()
    {
        return Test(m_a.m_t * m_b.m_t);
    }
};

class DivTest : public CalTest
{
public:
    DivTest(Test a, Test b) : CalTest(a,b)
    {
    }
    virtual Test get_result()
    {
        return Test(m_a.m_t / m_b.m_t);
    }
};

class ModTest : public CalTest
{
public:
    ModTest(Test a, Test b) : CalTest(a,b)
    {
    }
    virtual Test get_result()
    {
        return Test(m_a.m_t % m_b.m_t);
    }
};

class CalFactory  //这个计算工厂类,是为了将op这个变化点封装起来,下面继承的就相当于各个小车间,实现产生指针的加减乘除
{
public:
    virtual Cal *createOperator(double a, double b) = 0;
    virtual CalTest *createTest(Test a, Test b) = 0;
};

class AddFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Add(a,b);  //进行构造,并给m_a,m_b传值
    }
    virtual CalTest *createTest(Test a, Test b)
    {
        return new AddTest(a,b);
    }
};

class SubFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Sub(a,b);
    }
    virtual CalTest *createTest(Test a, Test b)
    {
        return new SubTest(a,b);
    }
};

class MulFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Mul(a,b);
    }
    virtual CalTest *createTest(Test a, Test b)
    {
        return new MulTest(a,b);
    }
};

class DivFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Div(a,b);
    }
    virtual CalTest *createTest(Test a, Test b)
    {
        return new DivTest(a,b);
    }
};

class ModFactory : public CalFactory
{
public:
    virtual Cal * createOperator(double a, double b)override
    {
        return new Mod(a,b);
    }
    virtual CalTest *createTest(Test a, Test b)
    {
        return new ModTest(a,b);
    }
};

int main(int argc, char **argv)
{
    string op;
    double a;
    double b;

    cout<<"please input a : ";
    cin>>a;
    cout<<"please input b : ";
    cin>>b;
    cout<<"please input op : ";
    cin>>op;

    IocContainer<CalFactory>con;
    con.RegisterType<AddFactory>("+");
    con.RegisterType<SubFactory>("-");
    con.RegisterType<MulFactory>("*");
    con.RegisterType<DivFactory>("/");
    con.RegisterType<ModFactory>("%");
    //["+",[](){return new AddFactory;}], ["-",[](){return new SubFactory;}]
    //["*",[](){return new MulFactory;}], ["/",[](){return new DivFactory;}]
    //["%",[](){return new ModFactory;}]

    CalFactory *factory = con.Resolve(op);

    Cal *cal = factory->createOperator(a,b);
    CalTest *tcal = factory->createTest(Test(a),Test(b));
    cout<<"result(double) = "<<cal->get_result()<<endl;
    cout<<"result(Test) = "<<tcal->get_result()<<endl;

    return 0;
}

版本八:

        思路:本版本主要是利用第三方已经写好的四则运算方法,新增一个派生类Adapet,继承前面的基类,并在该派生类Adapet组合进来第三方的类对象(MyCal cal),在该派生类的覆写函数中,具体的实现是通过调用第三方的类对象(MyCal cal)的函数方法实现的;

        耦合度:低,扩展型好;

        优点:重点可以利用第三方已经写好的代码,通过新增一个类继承上面的基类,并组合进来该第三方类的对象,在覆写函数方法时,具体实现是调用第三方的函数接口;

        缺点:暂无;

cpp:

#include <iostream>
#include <string>
#include <memory>
#include "mycal.hpp"

using namespace std;

class Cal  //先有一个基类,加减乘除继承,实现具体方法
{
public:
    Cal(double a, double b) : m_a(a), m_b(b)
    {
    }
    virtual ~Cal()
    {
    }
    virtual double get_result() = 0;
    double m_a;
    double m_b;
};

class Add : public Cal
{
public:
    Add(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a + m_b;
    }
};

class Sub : public Cal
{
public:
    Sub(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a - m_b;
    }
};

class Mul : public Cal
{
public:
    Mul(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a * m_b;
    }
};

class Div : public Cal
{
public:
    Div(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a / m_b;
    }
};

class Mod : public Cal
{
public:
    Mod(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return double((int)m_a % (int)m_b);
    }
};

class AddAdapet : public Cal
{
public:
    AddAdapet(double a, double b, string op) : Cal(a,b), cal(a,b) ,m_op(op)
    {
    }
    virtual double get_result()
    {
        return cal.excute(m_op);  //调用的第三方接口
    }

    string m_op;  //为了适配MyCal中的excute函数,额外补充了一个m_op成员,作为第三方接口传参
    MyCal cal;    //将第三方接口组合进来,通过该成员可以调用第三方接口
};

int main(int argc, char ** argv)
{
    string op;
    double a;
    double b;

    cout<<"please input a : ";
    cin>>a;
    cout<<"please input b : ";
    cin>>b;
    cout<<"please input op : ";
    cin>>op;

    Cal *cal = new AddAdapet(a,b,op);  //通过基类的指针调用派生类的指针,而派生列又是组合的第三方的函数方法;

    cout<< cal->get_result() <<endl;

    return 0;
}

hpp:

#include <iostream>

using namespace std;

class MyCal
{
public:
    MyCal(double a, double b) : m_a(a),m_b(b)
    {
    }

    double excute(string op)
    {
        if(op == "+")
        {
            return m_a + m_b;
        }
        else if(op == "-")
        {
            return m_a - m_b;
        }
        else if(op == "*")
        {
            return m_a * m_b;
        }
        else if(op == "/")
        {
            return m_a / m_b;
        }
        else if(op == "%")
        {
            return double((int)m_a % (int)m_b);
        }
        return 0;
    }

    double m_a;
    double m_b;
};

版本九:

        思路:本版本是在版本2的基础上,设置了“代理类”,代理类的作用就是设置相关的条件,例如只计算1-10之间的四则运算;

        耦合度:高,new放到了主函数,与类名耦合度高;

        优点:通过代理类方便设置计算条件;

        缺点:耦合度高,又将new放到了主函数,并且与类名高度耦合;

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Cal  //先有一个基类,加减乘除继承,实现具体方法
{
public:
    Cal(double a, double b) : m_a(a), m_b(b)
    {
    }
    virtual ~Cal()
    {
    }
    virtual double get_result() = 0;
    double m_a;
    double m_b;
};

class Add : public Cal
{
public:
    Add(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a + m_b;
    }
};

class Sub : public Cal
{
public:
    Sub(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a - m_b;
    }
};

class Mul : public Cal
{
public:
    Mul(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a * m_b;
    }
};

class Div : public Cal
{
public:
    Div(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return m_a / m_b;
    }
};

class Mod : public Cal
{
public:
    Mod(double a, double b) : Cal(a,b)
    {
    }
    double get_result()override
    {
        return double((int)m_a % (int)m_b);
    }
};

class CalSubject : public Cal  //这里相当于一个总代理接口,代理的是基类指针,统一管理
{
public:
    CalSubject(Cal *cal) : Cal(0, 0),m_cal(cal)  //接收的基类的指针;
    {
    }
    virtual double get_result()
    {
        if((m_cal->m_a >= 1) && (m_cal->m_a <= 10))  //设置条件
        {
            return m_cal->get_result();
        }
        else 
        {
            throw("the num >10 or <1!");
        }
    }

private:
    Cal * m_cal;  //上面继承,这里又通过组合的方式,有一个基类指针成员,可以调用派生类的方法
};

int main(int argc, char **argv)
{
    string op;
    double a;
    double b;

    cout<<"please input a : ";
    cin>>a;
    cout<<"please input b : ";
    cin>>b;
    cout<<"please input op : ";
    cin>>op;

    Cal *cal;
    if(op == "+")  //缺点就是又将new放到了主函数,并且与类名高度耦合;
    {
        cal = new Add(a,b);  //先构造Add指针,给m_a,m_b赋值,将指针交给基类指针调用
    }
    else if(op == "-")
    {
        cal = new Sub(a,b);
    }
    else if(op == "*")
    {
        cal = new Mul(a,b);
    }
    else if(op == "/")
    {
        cal = new Div(a,b);
    }
    else if(op == "%")
    {
        cal = new Mod(a,b);
    }

    CalSubject subject (cal);
    cout<<"result = "<<cal->get_result()<<endl;

    return 0;
}

3. 结构性模式

        (1)包装器模式

        ①定义:以透明动态的方式来动态扩展对象的功能;

        ②举例,比如已经定义好了一个“奶茶类”,但是购买奶茶的人往往都要在奶茶里加入红豆、燕麦等等;

#include <iostream>
#include <sstream>
using namespace std;
template <class T>
string MyConvertToStr(T obj) 
{
  stringstream ss;
  ss << obj;
  return ss.str();
}
 
class Beverage  //饮料抽象类 
{
public:
    virtual string getDescription() = 0;  //描述 
    virtual double cost() = 0;  //计价 
protected:
    string m_Description;  //描述语言 
};

class Lattee :public Beverage
{
public:
  Lattee() 
  {
     m_Description = "拿铁";  //赋值 
  }
  string getDescription() 
  {
     return m_Description;
  }
  double cost() 
  {
     return 13;
  }
};
 
 
class Expresso :public Beverage 
{
public:
  Expresso() 
  {
     m_Description = "浓缩咖啡";
  }
  string getDescription() 
  {
     return m_Description;
  }
  double cost() 
  {
     return 13;
  }
};
 
class Mocha :public Beverage 
{
public:
  Mocha() 
  {
     m_Description = "抹茶";
  }
  string getDescription() 
  {
     return m_Description;
  }
  double cost() 
  {
     return 13;
  }
};

class CondimentDecorate :public Beverage   //??这是什么作用?? 
{
public:
    virtual string getDescription() = 0;
protected:
    CondimentDecorate(){}
};

//装饰类1:Soy
class Soy :public CondimentDecorate 
{
public:
  Soy(Beverage *pBeverage):m_pBeverage(pBeverage){}
  string getDescription() 
  {
     return m_pBeverage->getDescription() + ",加了酱油了";  //动态扩展功能(这里是描述增加了); 
  }
  double cost() 
  {
     return 0.1 + m_pBeverage->cost();  //价格中也有体现
  }
private:
  //持有被装饰的对象
  Beverage *m_pBeverage;
};
 
//装饰类2:Milk
class Milk :public CondimentDecorate 
{
public:
  Milk(Beverage *pBeverage) :m_pBeverage(pBeverage) {}
  string getDescription() 
  {
     return m_pBeverage->getDescription() + ",加了牛奶了";
 
  }
  double cost() 
  {
     return 5+ m_pBeverage->cost();
  }
private:
  //持有被装饰的对象
  Beverage *m_pBeverage;
};

//装饰类2:xuebi 
class Xuebi :public CondimentDecorate 
{
public:
  Xuebi(Beverage *pBeverage) :m_pBeverage(pBeverage) {}
  string getDescription() 
  {
     return m_pBeverage->getDescription() + ",加了肥仔快乐水";
 
  }
  double cost() 
  {
     return 3+ m_pBeverage->cost();
  }
private:
  //持有被装饰的对象
  Beverage *m_pBeverage;
};
 
int main(void) 
{
  Beverage* p1 = new Expresso();  //浓缩咖啡 
  cout << p1->getDescription() << "价格是" << MyConvertToStr(p1->cost()) << endl;
 
  Beverage* p2 = new Mocha();  //抹茶 
  p2 = new Soy(p2);
  p2 = new Xuebi(p2);
  cout << p2->getDescription() << "价格是" << MyConvertToStr(p2->cost()) << endl;
  system("pause");

  return 0;
}

        (2)桥接模式(类发生变化时,与成员对象之间的解耦),是典型的合成复用原则(优先使用组合),当继承关系是复杂的树形结构,要用桥接解耦,适用于多维度同时变化;

4. 行为型模式

        (1)策略模式,聊天室就是典型的策略模式,组合多个抽象类;

        优点:使用策略模式可以避免使用多重条件转移语句,因为多重转移不易维护。

        缺点:会造成很多的策略类,每个具体的策略类都会产生一个新类;

例子,鸭子功能组合游戏:


#include <iostream>
using namespace std;

//设计思想:我们父类和子类就是一个扩展的关系?是不是合适
//里氏代换原则:子类对象就应该能完全替代父类的行为
//对于继承这样设计,特别小心,我们:组合大于继承
//把quack和fly抽象成为一个对象,那么这个问题就了解决方案


//
//完成了将“动作”抽象成“对象”

class FlyBehavior 
{
public:
	virtual void fly() = 0;
protected:
	FlyBehavior(){}
};

class FlyWithRocket :public FlyBehavior 
{
	void fly() 
	{
		cout << "做着火箭飞" << endl;
	}
};

class FlyWithWings :public FlyBehavior 
{
	void fly() 
	{
		cout << "我有翅膀可以自己飞" << endl;
	}
};

class FlyWithNoWay :public FlyBehavior 
{
	void fly() 
	{
		cout << "我根本就会飞" << endl;
	}
};

class QuackBehavior 
{
public:
	virtual void quack() = 0;
protected:
	QuackBehavior(){} 
};

class ZhiZhiQuack :public QuackBehavior 
{
public:	void quack() 
    {
	cout << "吱吱" << endl;
	}
};

class PersonQuack :public QuackBehavior 
{
public:
	void quack() 
	{
		cout << "我是唐唐姥姥" << endl;
	}
};

class WigeonQuack :public QuackBehavior
{
public:
	void quack() 
	{
		cout << "丑小鸭变天鹅" << endl;
	}
};

//Duck has a Quack 
//     has a Fly
class Duck 
{
public:
	virtual void Display() = 0;
	void setFlyBehavior(FlyBehavior* fb) 
	{
		m_pFly = fb;
	}
	void setQuackBehavior(QuackBehavior* qb) 
	{
		m_pQuack = qb;
	}

	virtual void perfomrFly() 
	{
		m_pFly->fly();

		//if (is 唐老鸭) {唐老鸭的飞行
		//if (is 小黄鸭){小黄鸭的飞行.....
	}

	virtual void performQuack() 
	{
		m_pQuack->quack();
	}
protected:  //组合了这两个类(基类指针) 
	QuackBehavior *m_pQuack;
	FlyBehavior *m_pFly;
private:
};
//DonaladDuck is Duck
class DonaladDuck :public Duck 
{
public:
	DonaladDuck() 
	{
		m_pFly = new FlyWithRocket;   //某一个FlyBehavior的实例
		m_pQuack = new PersonQuack();   //quack的实例 
	}
	void Display() 
	{
		perfomrFly();
		performQuack();
	}
	
};
//第一个困境:子类似乎不太那么像父类。。。
class RuberDuck : public Duck 
{
public:
	RuberDuck() 
	{
		m_pFly = new FlyWithNoWay();
		m_pQuack = new ZhiZhiQuack();
	}
	void Display() 
	{
		perfomrFly();
		performQuack();
	}
};

class WigeonDuck : public Duck 
{
public:
	WigeonDuck() 
	{
		m_pFly = new FlyWithWings;
		m_pQuack = new WigeonQuack;
	}
	void Display() 
	{
		perfomrFly();
		performQuack();
	}
	
};

int main() 
{
	Duck *pDonlad = new RuberDuck;
	pDonlad->Display();
	system("pause");
	return 0;
}

        (2)观察者模式

        ①定义:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在它的状态发生变化时,会通知所有的观察者;

        ②适用场景:触发联动,当修改目标状态时就会触发相应的统治,然后会循环调用所有注册的观察者对象的相应方法;当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合;

③优点:满足“开-闭原则”,具体主题和具体观察者是松耦合关系;

缺点:如果一个观察者对象有很多的直接和观察的观察者的话,将所有的观察者都通知会花费很多时间,造成性能浪费;

示例如下:

#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>

using namespace std;

// 抽象一个Subject主题
// 观察者

class Observer
{
public:
    virtual void update(string m_Temp, string m_Humi) = 0;

protected:
    Observer() {}
};

class Subject
{
public:
    virtual void registerObserver(Observer *pObj) = 0;
    virtual void removeObserver(Observer *pObj) = 0;
    virtual void noitfyObserver() = 0;

protected:
    Subject() {}
};

class WeatherData : public Subject
{
public:
    WeatherData(string Temp, string Humi) : m_Temp(Temp), m_Humi(Humi)
    {
    }

    void registerObserver(Observer *pObj)
    {
        m_observers.push_back(pObj);
    }

    void removeObserver(Observer *pObj)
    {
        // auto iter = find(m_observers.begin(), m_observers.end(), pObj);
        // if (iter != m_observers.end())
        // {
        //     m_observers.erase(iter);
        // }
        for(auto iter = m_observers.begin(); iter != m_observers.end(); )
        {
            if((*iter) == pObj)
            {
                m_observers.erase(iter);
                // return;
            }
            else
            {
                iter++;  //注意iter是循环条件,上面if里面删除了符合条件的iter,会影响循环条件,所以要报iter++放在else里面;
            }
        }
    }

    void noitfyObserver()
    {
        // 逐个遍历调用Observer的update方法
        for (vector<Observer *>::iterator iter = m_observers.begin(); iter != m_observers.end(); iter++)
        {
            (*iter)->update(m_Temp, m_Humi);
        }
    }

    void setData(string Temp, string Humi)
    {
        m_Temp = Temp;
        m_Humi = Humi;
        noitfyObserver();
    }

private:
    vector<Observer *> m_observers;
    string m_Temp; // 温度
    string m_Humi; // 湿度
};

// CocreteObserver
class PCDisplay : public Observer
{
public:
    PCDisplay(WeatherData *pWeatherData)
    {
        m_pWeatherData = pWeatherData;
        m_pWeatherData->registerObserver(this);
    }

    void update(string m_Temp, string m_Humi)
    {
        cout << "我是PC端的显示GUI,当前的温度为" << m_Temp << ", 湿度为" << m_Humi << endl;
    }

private:
    WeatherData *m_pWeatherData;
};

class MobileDisplay : public Observer
{
public:
    MobileDisplay(WeatherData *pWeatherData)
    {
        m_pWeatherData = pWeatherData;
        m_pWeatherData->registerObserver(this);
    }

    void update(string m_Temp, string m_Humi)
    {
        cout << "我是Mobile端的显示GUI,当前的温度为" << m_Temp << ", 湿度为" << m_Humi << endl;
    }

private:
    WeatherData *m_pWeatherData;
};

int main(void)
{
    WeatherData *pWD = new WeatherData("22C", "65%");

    PCDisplay *pPCDisplay = new PCDisplay(pWD);
    MobileDisplay *pMobile = new MobileDisplay(pWD);

    pWD->setData("38C", "55%");    //设置温度和湿度,并利用两个派生类(移动端、PC端)显示;
    pWD->removeObserver(pMobile);  //删除移动端;

    pWD->setData("31C", "44%");    //重新设置温度、湿度;

    // system("pause");
    getchar();
    return 0;
}

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值