设计模式

61 阅读10分钟

面向对象设计原则

背案例而不是背原则,主打一个高内聚,低耦合。

开闭原则

对拓展开放,对修改关闭,增加功能是通过增加代码实现的,而不是去修改源代码

#include <iostream>

//写一个抽象类
class AbstractCalculator{
public:
    virtual int getResult() = 0;
    virtual void setOperatorNumber(int a,int b) = 0;
};

//加法器类
class PlusCalculator:public AbstractCalculator{
public:
    int m_A;
    int m_B;

    void setOperatorNumber(int a,int b){
        this->m_A=a;
        this->m_B=b;
    }
    int getResult(){
        return m_A+m_B;
    }
};

//减法器类
class SubstractCalculator:public AbstractCalculator{
public:
    int m_A;
    int m_B;

    void setOperatorNumber(int a,int b){
        this->m_A=a;
        this->m_B=b;
    }
    int getResult(){
        return m_A-m_B;
    }
};


//乘法器类
class MultiplyCalculator:public AbstractCalculator{
public:
    int m_A;
    int m_B;

    void setOperatorNumber(int a,int b){
        this->m_A=a;
        this->m_B=b;
    }
    int getResult(){
        return m_A*m_B;
    }
};


void test01(){
    PlusCalculator pc;
    pc.setOperatorNumber(10,20);
    std::cout << "result: " << pc.getResult() << std::endl;

}

int main(){
    test01();
}

迪米特法则

又叫最少知识原则,尽量保留不暴露过多的数据。比如,我只想要品质信息,那你就专门弄一个关于品质的中介,而不是我直接去访问所有的实例。最小暴露原则。

#include <iostream>
#include <string>
#include <vector>

//迪米特原则:又叫最少知识原则,尽量保留不暴露过多的数据
//我只想要品质信息,那你就专门弄一个关于品质的中介,而不是我直接去访问所有的实例

class AbstractBuilding {
public:
    virtual void sale() = 0;
    virtual std::string getQuality() = 0;
};

//楼盘A
class BuildingA : public AbstractBuilding {
public:
    std::string m_Quality;
    BuildingA() {
        m_Quality = "高品质";
    }
    void sale() {
        std::cout << "楼盘A" << m_Quality << "被售卖" << std::endl;
        return;
    }
    std::string getQuality(){
        return m_Quality;
    }
};

//楼盘B
class BuildingB : public AbstractBuilding {
public:
    std::string m_Quality;
    BuildingB() {
        m_Quality = "低品质";
    }
    void sale() {
        std::cout << "楼盘B" << m_Quality << "被售卖" << std::endl;
        return;
    }
    std::string getQuality(){
        return m_Quality;
    }
};

//直接暴露实例
void test01() {
    BuildingA ba;
    if (ba.m_Quality == "低品质") {
        ba.sale();
    }
    BuildingB bb;
    if (bb.m_Quality == "低品质") {
        bb.sale();
    }
}

//中介类
class Mediator {
public:
    std::vector<AbstractBuilding *> vBuilding;
    Mediator() {
        AbstractBuilding *building = new BuildingA;
        vBuilding.push_back(building);
        building = new BuildingB;
        vBuilding.push_back(building);
    }
    ~Mediator() {
        for (std::vector<AbstractBuilding *>::iterator it = vBuilding.begin(); it != vBuilding.end(); it++) {
            if (*it != NULL) {
                delete *it;
            }
        }
    }
    //对外提供接口
    AbstractBuilding *fingMyBuilding(std::string quality) {
        for (std::vector<AbstractBuilding *>::iterator it = vBuilding.begin(); it != vBuilding.end(); it++) {
            if ((*it)->getQuality()==quality) {
                return *it;
            }
        }
        return nullptr;
    }
};

//通过中介类获取信息
void test02(){
    Mediator mediator;
    AbstractBuilding* building =mediator.fingMyBuilding("高品质");
    if(building!=NULL){
        building->sale();
    }else{
        std::cout << "没有符合您条件的楼盘" << std::endl;
    }
}

int main() {
    test01();
    test02();
    return 0;
}

合成复用原则

泛化(继承) 和 组合 优先使用组合,简称少用继承

// 泛化(继承) 和 组合 优先使用组合,简称少用继承
#include <iostream>

class AbstractCar{
public:
    virtual void run()=0;
};

//大众
class Dazhong:public AbstractCar{
public:
    void run(){
        std::cout << "大众,启动" << std::endl;
    }
};

//拖拉机
class Tuolaji:public AbstractCar{
public:
    void run(){
        std::cout << "拖拉机,启动" << std::endl;
    }
};

//使用泛化关系
#if 0
//这样每次都要换车
class Person:public Tuolaji{
public:
    void Doufeng(){
        run();
    }
};

class PersonB:public Dazhong{
public:
    void Doufeng(){
        run();
    }
};
#endif


//使用组合
class Person{
public:
    AbstractCar *car;
    void setCat(AbstractCar* car){
        this->car=car;
    }
    void Doufeng(){
        car->run();
        if(car!=NULL){
            delete car;
        }
    }
};

void test01(){
    Person p;
    p.setCat(new Dazhong);
    p.Doufeng();
    p.setCat(new Tuolaji);
    p.Doufeng();
}

int main(){
    test01();
}

依赖倒转原则

依赖不要用具体实现,而要用抽象类,保证拓展性

//依赖不要用具体实现,而要用抽象类,保证拓展性

#include <iostream>

class AbstractWorker {
public:
    virtual void doBusiness() = 0;
};

//这里运用了开闭原则,模仿计算器案例进行实现
//专门办理存款业务的工作人员
class SaveBankWorker: public AbstractWorker{
public:
    void doBusiness(){
        std::cout << "办理存款业务" << std::endl;
    }
};

//专门办理支付业务的工作人员
class PayBankWorker: public AbstractWorker{
public:
    void doBusiness(){
        std::cout << "办理支付业务" << std::endl;
    }
};

//专门办理转账业务的工作人员
class TransferWorker:public AbstractWorker{
public:
    void doBusiness(){
        std::cout << "办理转账业务" << std::endl;
    }
};

//中层模块
void doNewBusiness(AbstractWorker* worker){
    worker->doBusiness();
    if(worker!= nullptr){
        delete worker;
    }
}


//业务模块
void test01(){
    doNewBusiness(new TransferWorker);
    doNewBusiness(new SaveBankWorker);
}

int main(){
    test01();
}

常用的设计模式

工厂模式

简单工厂模式

不要直接去创建类,而是通过和工厂交互,让工厂生产,使得我不需要知道创建细节
但是简单工厂添加新的水果时明显不符合开闭原则

#include <iostream>

class AbstractFruit{
public:
    virtual void showName() = 0;
};

class Apple:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是苹果" << std::endl;
    }
};

class Pear:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是梨" << std::endl;
    }
};

class Banana:public AbstractFruit{
    void showName(){
        std::cout << "我是香蕉" << std::endl;
    }
};

class FruitFactory{
public:
    static AbstractFruit* createFruit(std::string flag){
        if(flag=="apple"){
            return new Apple;
        }else if(flag=="banana"){
            return new Banana;
        }else if(flag=="pear"){
            return new Pear;
        }else{
            return NULL;
        }
    }
};


void test01(){
    FruitFactory* factory = new FruitFactory;
    AbstractFruit* fruit = factory->createFruit("apple");
    fruit->showName();
    delete fruit;

    fruit = factory->createFruit("pear");
    fruit->showName();
    delete fruit;

    fruit = factory->createFruit("banana");
    fruit->showName();
    delete fruit;
}

int main(){
    test01();
}

工厂方法模式

简单工厂的工厂不符合开闭原则,把工厂符合开闭原则就是工厂方法模式
唯一优点:符合开闭
缺点:类太多,一个水果一个工厂

#include <iostream>

class AbstractFruit{
public:
    virtual void showName() = 0 ;
};

class Apple:public AbstractFruit{
    void showName(){
        std::cout << "我是苹果!" << std::endl;
    }
};

class Pear:public AbstractFruit{
    void showName(){
        std::cout << "我是梨!" << std::endl;
    }
};

class Banana:public AbstractFruit{
    void showName(){
        std::cout << "我是香蕉!" << std::endl;
    }
};


class AbstractFruitFactory{
public:
    virtual AbstractFruit* createFruit()=0;
};

//苹果工厂
class AppleFactory:public AbstractFruitFactory{
    AbstractFruit* createFruit(){
        return new Apple;
    }
};

//香蕉工厂
class BananaFactory:public AbstractFruitFactory{
    AbstractFruit* createFruit(){
        return new Banana;
    }
};

//梨工厂
class PearFactory:public AbstractFruitFactory{
    AbstractFruit* createFruit(){
        return new Pear;
    }
};


void test01(){
    AbstractFruitFactory* factory=NULL;
    AbstractFruit* fruit=NULL;

    factory=new AppleFactory;
    fruit=factory->createFruit();
    fruit->showName();
    delete factory;
    delete fruit;

    factory=new PearFactory;
    fruit=factory->createFruit();
    fruit->showName();
    delete factory;
    delete fruit;

    factory=new BananaFactory;
    fruit=factory->createFruit();
    fruit->showName();
    delete factory;
    delete fruit;

}

int main(){
    test01();
}

抽象工厂模式

抽象工厂模式相当于对简单工厂进行抽象
添加产品族符合开闭原则,添加产品等级结构不符合开闭原则

产品族和产品等级结构

image.png

  • 产品组:横着的一行,同一产地或者统一厂商,功能不同
  • 产品等级:竖着的一列,功能相同,产地或者产商不同
#include <iostream>

class AbstractFruit{
public:
    virtual void showName() = 0;
};


class ChinaApple:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是中国苹果" << std::endl;
    }
};

class ChinaBanana:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是中国香蕉" << std::endl;
    }
};

class ChinaPear:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是中国梨" << std::endl;
    }
};


class USAApple:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是美国苹果" << std::endl;
    }
};

class USABanana:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是美国香蕉" << std::endl;
    }
};

class USAPear:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是美国梨" << std::endl;
    }
};

class JapanApple:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是日本苹果" << std::endl;
    }
};

class JapanBanana:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是日本香蕉" << std::endl;
    }
};

class JapanPear:public AbstractFruit{
public:
    void showName(){
        std::cout << "我是美国日本梨" << std::endl;
    }
};

class AbstractFruitFactory{
public:
    virtual AbstractFruit* createApple()=0;
    virtual AbstractFruit* createBanana()=0;
    virtual AbstractFruit* createPear()=0;
};

class ChinaFruitFactory:public AbstractFruitFactory{
public:
    AbstractFruit* createApple() {
        return new ChinaApple;
    }
    AbstractFruit* createBanana(){
         return new ChinaBanana;
    }
    AbstractFruit* createPear(){
        return new ChinaPear;
    }
};

class USAFruitFactory:public AbstractFruitFactory{
    AbstractFruit* createApple() {
        return new USAApple;
    }
    AbstractFruit* createBanana(){
        return new USABanana;
    }
    AbstractFruit* createPear(){
        return new USAPear;
    }
};

class JapanFruitFactory:public AbstractFruitFactory{
    AbstractFruit* createApple() {
        return new JapanApple;
    }
    AbstractFruit* createBanana(){
        return new JapanBanana;
    }
    AbstractFruit* createPear(){
        return new JapanPear;
    }
};

void test01(){
    AbstractFruitFactory* fruitFactory=NULL;
    AbstractFruit* apple=NULL;
    AbstractFruit* banana=NULL;
    AbstractFruit* pear=NULL;

    fruitFactory=new ChinaFruitFactory;
    apple=fruitFactory->createApple();
    banana=fruitFactory->createBanana();
    pear=fruitFactory->createBanana();
    apple->showName();
    banana->showName();
    pear->showName();

    delete fruitFactory;
    delete apple;
    delete banana;
    delete pear;
}


int main(){
    test01();
}

单例模式

保证一个类只有一个实例,比如你只需要一个管理者。你只需要搞一个全局共享的实例,只能通过规定的方式创建,而不能随意创建。

单例模式的一般步骤

  1. 私有化构造函数(不能随意创建)
  2. 私有化静态变量指针
  3. 公有化静态接口,可以让用户获得单粒对象
#include <iostream>

//单例模式的一般思路
class A{
private:
    static A* a;
    A(){}
public:
    static A* getInstance(){
        return a;
    }
};

A* A::a=new A;


//饿汉式和懒汉式
//两者的区别在于对象创建时机

//懒汉式,要使用的时候才创建,线程不安全 
class Singleton_lazy{
private:
    static Singleton_lazy* singletonLazy;
    Singleton_lazy(){
            std::cout << "懒汉式执行" << std::endl;
    };
public:
    static Singleton_lazy* getInstance(){
        if(singletonLazy== nullptr){
            singletonLazy=new Singleton_lazy;
        }
        return singletonLazy;
    }
};
Singleton_lazy* Singleton_lazy::singletonLazy= nullptr;

//饿汉式,早于主函数执行之前就创建好了,线程安全
class Singleton_hungry{
private:
    static Singleton_hungry* singletonHungry;
    Singleton_hungry(){
            std::cout << "饿汉式创建" << std::endl;
    };
public:
    static Singleton_hungry* getInstance(){
        return singletonHungry;
    }
};
Singleton_hungry* Singleton_hungry::singletonHungry=new Singleton_hungry;

void test01(){
    //验证饿汉式和懒汉式的创建时机
    Singleton_lazy* p=Singleton_lazy::getInstance();
}

void test02(){
    //验证是否真的是唯一单例
    Singleton_lazy* p1=Singleton_lazy::getInstance();
    Singleton_lazy* p2=Singleton_lazy::getInstance();
    if(p1==p2){
        std::cout << "唯一单例" << std::endl;
    }
}


int main(){
    std::cout << "主函数执行" << std::endl;
    test01();
    test02();
}

代理模式

提供一种代理来看控制对其他对象的访问

#include <iostream>
//代理就是在系统之上再加一层 -> 代理 = 系统 + 一些东西 -> 代理包含系统
//你可以直接理解为代理就是系统
//基于这个原理,那么代理和系统必须具有相同的接口
class AbstractCommonInterface{
public:
    virtual void run()=0;
};

//必须要有权限验证,而不是所有人都能访问我的系统,必须提供用户名和密码
class MySystem:public AbstractCommonInterface{
public:
    void run(){
        std::cout << "系统启动" << std::endl;
    }
};



class MySystemProxy:public AbstractCommonInterface{
public:
    MySystemProxy(std::string userName,std::string password){
        this->userName=userName;
        this->password=password;
        pMySystem=new MySystem;
    }
    void run(){
        if(userName=="admin" && password=="admin"){
            pMySystem->run();
        }else{
            std::cout << "系统权限不足" << std::endl;
        }
    }
    ~MySystemProxy(){
        if(pMySystem!= nullptr){
            delete pMySystem;
        }
    }
private:
    std::string userName;
    std::string password;
    MySystem* pMySystem;
};

void test01(){
    MySystemProxy* proxy=nullptr;
    proxy=new MySystemProxy("root","admin");
    proxy->run();
    delete proxy;

    proxy=new MySystemProxy("admin","admin");
    proxy->run();
    delete proxy;

}

int main(){
    test01();
}

外观模式

满足迪米特原则,也就是最小暴露原则,你暴露一个接口让我直接实现想要的功能就行,我不想知道里面有什么东西

#include <iostream>



class Television{
public:
    void On(){
        std::cout << "电视机打开..." << std::endl;
    }
    void Off(){
        std::cout << "电视机关闭..." << std::endl;
    }
};

class Light{
public:
    void On(){
        std::cout << "灯打开..." << std::endl;
    }
    void Off(){
        std::cout << "灯关闭..." << std::endl;
    }
};

class Audio{
public:
    void On(){
        std::cout << "音箱打开..." << std::endl;
    }
    void Off(){
        std::cout << "音箱关闭..." << std::endl;
    }
};

class Microphone{
public:
    void On(){
        std::cout << "麦克风打开..." << std::endl;
    }
    void Off(){
        std::cout << "麦克风关闭..." << std::endl;
    }
};

class DVDPlayer{
public:
    void On(){
        std::cout << "DVD播放器打开..." << std::endl;
    }
    void Off(){
        std::cout << "DVD播放器关闭..." << std::endl;
    }
};

class GamePlayer{
public:
    void On(){
        std::cout << "游戏机打开..." << std::endl;
    }
    void Off(){
        std::cout << "游戏机关闭..." << std::endl;
    }
};

class KTVMode{
public:
    Television* pTV;
    Light* pLight;
    Audio* pAudio;
    Microphone* pMicrophone;
    DVDPlayer* pDvdPlayer;
    KTVMode(){
        pTV=new Television;
        pLight=new Light;
        pAudio=new Audio;
        pMicrophone=new Microphone;
        pDvdPlayer=new DVDPlayer;
    }
    ~KTVMode(){
        delete pDvdPlayer;
        delete pMicrophone;
        delete pAudio;
        delete pLight;
        delete pTV;
    }
    void onKTVMode(){
        pTV->On();
        pLight->On();
        pAudio->On();
        pMicrophone->On();
        pDvdPlayer->On();
    }
    void offKTVMode(){
        pTV->Off();
        pLight->Off();
        pAudio->Off();
        pMicrophone->Off();
        pDvdPlayer->Off();
    }
};

适配器模式

不如叫转接口模式
比如将 双参数函数 转接为 单参数函数
思路:双参数函数 封装成 单参数函数,然后内部一个参数固定

#include <iostream>
#include <vector>
#include <algorithm>


class MyPrint{
public:
    int operator()(int a,int b){
        return a+b;
    }
};

class Adapter{
public:
    MyPrint myPrint;
    int param;
    Adapter(int param){
        this->param=param;
    }
    int operator()(int v){
        return myPrint(v,param);
    }
};

Adapter MyBind2nd(int a){
    return Adapter(a);
}

int main(){
    std::vector<int> v;
    for(int i=0;i<10;i++){
        v.push_back(i);
    }
    Adapter adapter= MyBind2nd(20);
    std::for_each(v.begin(),v.end(),adapter);
}

模版方法模式

步骤相同,只是每个步骤需要特定的实现

#include <iostream>
class DrinkTemplate{
public:
    //煮水
    virtual void boilWater()=0;
    //冲泡
    virtual void brew()=0;
    //倒入杯中
    virtual void pourInCup()=0;
    //加辅料
    virtual void addSomething()=0;

    //模版方法
    void make(){
        boilWater();
        brew();
        pourInCup();
        addSomething();
    }
};

//冲泡咖啡
class Coffee:public DrinkTemplate{
public:
    //煮水
    virtual void boilWater(){
            std::cout << "煮山泉水" << std::endl;
    };
    //冲泡
    virtual void brew(){
            std::cout << "冲泡咖啡" << std::endl;
    };
    //倒入杯中
    virtual void pourInCup(){
            std::cout << "咖啡倒入杯中" << std::endl;
    };
    //加辅料
    virtual void addSomething(){
            std::cout << "加入牛奶" << std::endl;
    };
};

//冲泡茶
class Tea:public DrinkTemplate{
public:
    //煮水
    virtual void boilWater(){
        std::cout << "煮自来水" << std::endl;
    };
    //冲泡
    virtual void brew(){
        std::cout << "冲泡铁观音" << std::endl;
    };
    //倒入杯中
    virtual void pourInCup(){
        std::cout << "茶水倒入杯中" << std::endl;
    };
    //加辅料
    virtual void addSomething(){
        std::cout << "加入柠檬" << std::endl;
    };
};


void test01(){
    Tea* tea=new Tea;
    tea->make();

    Coffee* coffee=new Coffee;
    coffee->make();
}

int main(){
    test01();
}

策略模式

封装特定方法

//都拥有使用武器这一方法,那就封装一个武器策略
#include <iostream>

//也可以理解为抽象武器
class WeaponStrategy{
public:
    virtual void UseWeapon()= 0;
};


class AK47:public WeaponStrategy{
public:
    void UseWeapon(){
        std::cout << "使用AK47" << std::endl;
    }
};

class Knife:public WeaponStrategy{
public:
    void UseWeapon(){
        std::cout << "使用匕首" << std::endl;
    }
};

class Character{
public:
    WeaponStrategy* pWeapon;

    void setWeapon(WeaponStrategy* weaponStrategy){
        this->pWeapon=weaponStrategy;
    }
    void throwWeapon(){
        this->pWeapon->UseWeapon();
    }
};

void test01(){
    //创建角色
    Character* character=new Character;

    //武器策略
    WeaponStrategy* knife=new Knife;
    WeaponStrategy* ak47=new AK47;

    character->setWeapon(knife);
    character->throwWeapon();
    delete knife;

    character->setWeapon(ak47);
    character->throwWeapon();
    delete ak47;
}

int main(){
    test01();
}