c++ 设计模式

https://www.bilibili.com/video/BV1Mb411t7ut的笔记

设计模式

核心的问题:如何同时提高一个软件系统的可维护性和可复用性

原则的目的:高内聚,低耦合

  1. 单一职责原则

    类的职责单一,对外只提供一种功能,而引起类变化的原因应该只有一个

  2. 开闭原则

    类的改动是通过代码进行的,而不是修改原代码

  3. 里氏代换原则

    任何抽象类出现的地方都可以用他的实现类进行替换(多态)

  4. 依赖倒转原则

    依赖于抽象,不要依赖与具体的实现,对接口编程

  5. 接口隔离原则

    一个接口只提供一种对外的功能

  6. 合成复用原则

    对于继承和组合,优先使用组合(即作为一个参数或者是一个内部成员)

  7. 迪米特原则

    一个对象应当对其他对象尽可能少的了解,从而来降低偶和

简单工厂模式

通过一个工厂来创建要创建的类

好处:

  1. 客户端和具体实现类解耦
  2. 对于某些对象创建过程比较复杂的情况,我们也可以不去考虑(无需关心创建的过程)

不好:

  1. 简单工厂模式,增加新的功能是通过修改代码来实现的,不符合开闭原则
  2. 类的职责过重,若这个类发生问题,会影响很多使用这个工厂的模块

适用场景:

  1. 工厂类负责的对象比较少
  2. 客户端只知道传入工厂类的参数,对于如何创建对象不关心

案例

#include <iostream>

using namespace std;

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

class Apple : public abstractFruit {
public:
    void showName() override {
        cout << "i am apple" << endl;
    }
};

class Banana : public abstractFruit {
public:
    void showName() override {
        cout << "i am Banana" << endl;
    }
};

class FruitFactory {
public:
    static abstractFruit* CreateFruit(string flag) {
        if (flag == "apple") {
            return new Apple;
        } else {
            return new Banana;
        }
    }
};

void test01() {
    auto factory = new FruitFactory;
    auto apple = factory->CreateFruit("apple");
    auto banana = factory->CreateFruit("Banana");

    apple->showName();
    banana->showName();
}

int main() {
    test01();

    return 0;
}

工厂方法模式

将一个大的工厂抽象出来,然后每一个类都有一个对应的具体的工厂

缺点:

  1. 类的个数成倍增加(增加一个类,就要增加一个对应的工厂),从而导致类越来越多,增加了维护的成本
  2. 增加了系统的抽象性和理解难度

好处:

  1. 符合开闭原则
  2. 实现了对象创建和使用的分离
  3. 系统的可扩展性变得很好,无需修改接口和原类

使用场景:

  1. 客户端不知道他所需要的对象的类
  2. 抽象工厂类通过其子类来指定创建哪个对象
#include <iostream>

using namespace std;

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

class Apple : public abstractFruit {
public:
    void showName() override {
        cout << "i am apple" << endl;
    }
};

class Banana : public abstractFruit {
public:
    void showName() override {
        cout << "i am Banana" << endl;
    }
};


// 抽象工厂
class AbstractFactory {
public:
    virtual abstractFruit* CreateFruit() = 0;
};

//苹果工厂
class AppleFactory : public AbstractFactory {
public :
    abstractFruit* CreateFruit() override {
        return new Apple;
    }
};

//香蕉工厂
class BananaFactory : public AbstractFactory {
public :
    abstractFruit* CreateFruit() override {
        return new Banana;
    }
};


void test01() {
    AbstractFactory * factory = nullptr;
    abstractFruit* fruit = nullptr;

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

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

int main() {
    test01();

    return 0;
}

抽象工厂模式

抽象工厂针对的是产品族,而不是产品的等级结构

  • 产品族:同一产地或同一厂商,功能不同

  • 产品等级:功能相同,产地或者厂商不同

#include <iostream>

using namespace std;

// 抽象苹果
class abstractApple {
public:
    virtual void showName() = 0;
};

// 中国苹果
class chinaApple : public abstractApple {
public:
    void showName() override {
        cout << "中国苹果!" << endl;
    }
};

// 日子苹果
class japApple : public abstractApple {
public:
    void showName() override {
        cout << "日子苹果!" << endl;
    }
};

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

class chinaBanana : public abstractBanana {
public:
    void showName() override {
        cout << "中国香蕉!" << endl;
    }
};

class japBanana : public abstractBanana {
public:
    void showName() override {
        cout << "日子香蕉!" << endl;
    }
};

// 针对产品族
class abstractFactory {
public:
    virtual abstractApple* CreateApple() = 0;
    virtual abstractBanana* CreateBanana() = 0;
};

// 中国工厂
class chinaFactory : public abstractFactory {
public:
    abstractApple* CreateApple() override {
        return new chinaApple;
    }

    abstractBanana* CreateBanana() override {
        return new chinaBanana;
    }

};

// 日子工厂
class japFactory : public abstractFactory {
public:
    abstractApple* CreateApple() override {
        return new japApple;
    }

    abstractBanana* CreateBanana() override {
        return new japBanana;
    }

};

void test01() {
    auto fac = new chinaFactory;
    auto apple = fac -> CreateApple();
    auto banana = fac -> CreateBanana();
    apple->showName();
    banana -> showName();

    delete fac;
    delete apple;
    delete banana;
}


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

单例模式

单例模式只有一个实例, 并提供一个访问他的全局访问点

实现单例的步骤

  1. 构造函数私有化
  2. 增加静态私有的当前类的指针变量
  3. 提供一个静态的对外接口, 可以让用户获得单例对象

单例分为懒汉式饿汉式

单例对象释放的问题

  • 可以在对象中新建一个静态的 垃圾桶 ,通过 垃圾桶 的析构函数来释放单例对象
class singleton_hungry {
public:
    static singleton_hungry* getInstance() {
        return psingleton;
    }

    // 垃圾桶
    class Garbo {
        ~Garbo() {
            if (psingleton != nullptr)
                delete psingleton;
        }
    };
    
private:
    singleton_hungry() {
        cout << "我是饿汉式!" << endl;
    }
    static singleton_hungry* psingleton;
    static Garbo garbo;
};

多此一举!!!!因为当要销毁单例对象的时候,程序即将销毁,而当程序销毁的时候,单例对象自然会被销毁,所以无需手动销毁!!!!

代码演示

#include <iostream>
#include <algorithm>

using namespace std;

// 懒汉式-》只有当调用getInstance()的时候,才会new一个出来
class singleton_lazy {
public:
    static singleton_lazy* getInstance() {
        if (psingleton == nullptr) {
            psingleton = new singleton_lazy;
        }
        return psingleton;
    }

private:
    singleton_lazy() {
        cout << "我是懒汉式!" << endl;
    }
    static singleton_lazy* psingleton;
};

singleton_lazy* singleton_lazy::psingleton = nullptr;

// 饿汉式 -> 一开始就new一个
class singleton_hungry {
public:
    static singleton_hungry* getInstance() {
        return psingleton;
    }

private:
    singleton_hungry() {
        cout << "我是饿汉式!" << endl;
    }
    static singleton_hungry* psingleton;
};

singleton_hungry* singleton_hungry::psingleton = new singleton_hungry;

// 查看懒汉式和饿汉式是不是一个单例
void test01() {
    singleton_lazy* p1 = singleton_lazy::getInstance();
    singleton_lazy* p2 = singleton_lazy::getInstance();

    if (p1 == p2) {
        cout << "两个指针指向同一个内存" << endl;
    } else {
        cout << "两个指针不指向同一个内存" << endl;
    }

    singleton_hungry* p3 = singleton_hungry::getInstance();
    singleton_hungry* p4 = singleton_hungry::getInstance();

    if (p3 == p4) {
        cout << "两个指针指向同一个内存" << endl;
    } else {
        cout << "两个指针不指向同一个内存" << endl;
    }

}


int main() {
    cout << "main开始执行" << endl;
    test01();
    return 0;
}
单例模式遇到多线程
  • 懒汉式是线程不安全的(可能同时new很多个对象)
  • 饿汉式是线程安全的(对象在线程调用之前就已经创建好了)

代理模式

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

通过一个抽象类提供的一套相同的接口然后通过封装的方式,来实现通过对代理的访问来间接地访问真正的类。

#include <iostream>

using namespace std;

// 通过一种代理来控制对其他对象的访问

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

// 已经写好的系统
class MySystem : abstractCommonInterface{
public:
    void run() override {
        cout << "系统启动" << endl;
    }
};

// 不是所有的人都可以启动系统,若要启动系统,则必须输入帐号和密码
class MySystemProxy : public abstractCommonInterface {
public:
    MySystemProxy(string username, string password) {
        this->mUsername = username;
        this->mPassword = password;
        pSystem = new MySystem;
    }

    void run() override {
        if (checkUsernameAndPassword()) {
            cout << "正确, 系统系统" << endl;
            pSystem->run();
        } else {
            cout << "用户名或密码错误, 无法启动" << endl;
        }
    }

    // 只读函数可以用const来确保这个函数不会修改数据
    bool checkUsernameAndPassword() const {
        if (mUsername == "root" && mPassword == "root")
            return true;
        return false;
    }
    ~MySystemProxy() {
        delete pSystem;
    }
public:
    //将系统作为一个成员,对系统做一个封装
    MySystem* pSystem = nullptr;
    string mUsername;
    string mPassword;
};

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

    proxy = new MySystemProxy("root", "root");
    proxy->run();
}


int main() {
    test01();

    return 0;
}

外观模式

外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

封装的内容可以是相互之间毫无关联的东西,但是是一个共同的功能下的。

#include <iostream>

using namespace std;

// 外观模式

// 电视机
class Tv {
public:
    void On() {
        cout << "电视机打开" << endl;
    }

    void off() {
        cout << "电视机关闭" << endl;
    }
};

// 灯
class Light {
public:
    void On() {
        cout << "灯打开" << endl;
    }

    void off() {
        cout << "灯关闭" << endl;
    }
};

// 音响
class Audio {
public:
    void On() {
        cout << "音响打开" << endl;
    }

    void off() {
        cout << "音响关闭" << endl;
    }
};

// 通过这个类可以yi jian
class CinemaMode {
public:

    CinemaMode() {
        pTv = new Tv;
        pLight = new Light;
        pAudio = new Audio;
    }

    void onCinema() {
        pTv->On();
        pLight->off();
        pAudio->On();
    }

    void offCinema() {
        pTv->off();
        pLight->On();
        pAudio->off();
    }

    ~CinemaMode() {
        delete pTv;
        delete pLight;
        delete pAudio;
    }


    Tv* pTv;
    Light* pLight;
    Audio* pAudio;
};

void test01() {
    auto mode = new CinemaMode;
    mode->onCinema();
    cout << "//////////" << endl;
    mode->offCinema();
    delete mode;
}

int main() {
    test01();

    return 0;
}

适配器模式

在两个不兼容的接口之间搭建了一个桥梁,使得两个不同的接口可以使用。

代码实例

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

using namespace std;

// 若直接将这个函数传递进去, 则会报错
struct myPrint{
    void operator()(int v1, int v2) {
        cout << v1 + v2 << endl;
    }
};

// 定义目标接口:要适配成什么样子的。
class Target {
public:
    virtual void operator()(int v) = 0;
};

// 写适配器
class Adapter : public Target {
public:
    Adapter(int param) {
        this->param = param;
    }
    void operator()(int v) override {
        print(v, param);
    }
    myPrint print;
    int param;
};

// MyBind2nd
Adapter MyBind2nd(int v) {
    return Adapter(v);
}



int main() {
    vector<int> v;
    for (int i = 0; i < 10; i ++) {
        v.push_back(i);
    }

    for_each(v.begin(), v.end(), Adapter(10));
}

模板方法模式

一个抽象的类公开的定义了一个方法的模板。它的子类可以根据需要来重写这个方法,但调用将以抽象类中定义的方式进行。

好处:

  1. 父类形式化的定义一个算法,然后具体的实现的方法由子类来实现。
  2. 这是一种代码复用技术,他提取了类库中的公共行为,将公共行为放到父类中,然后其子类来实现各自不同的行为。
  3. 可以实现一种反向的控制,通过子类覆盖父类的函数,从而来防止某一步的执行。
  4. 符合单一职责原则和开闭原则。

代码实现

#include <iostream>
using namespace std;

class AbstractDrink {
public:
    // 煮水
    virtual void BoildWater() = 0;
    // 冲泡
    virtual void Brew() = 0;
    // 倒入杯中
    virtual void PourInTea() = 0;
    // 加入辅料
    virtual void AddSomeThing() = 0;

    // 模板方法
    void make() {
        BoildWater();
        Brew();
        PourInTea();
        AddSomeThing();
    }

};

class Coffee : public AbstractDrink {
public:
    // 煮水
    void BoildWater() override {
        cout << "烧水" << endl;
    }
    // 冲泡
    void Brew() override {
        cout << "冲泡" << endl;
    }
    // 倒入杯中
    void PourInTea() override {
        cout << "倒入杯中" << endl;
    }
    // 加入辅料
    void AddSomeThing() override {
        cout << "加入辅料" << endl;
    }
};

class Tea : public AbstractDrink {
public:
    // 煮水
    void BoildWater() override {
        cout << "烧茶" << endl;
    }
    // 冲泡
    void Brew() override {
        cout << "冲泡茶" << endl;
    }
    // 倒入杯中
    void PourInTea() override {
        cout << "倒入杯中" << endl;
    }
    // 加入辅料
    void AddSomeThing() override {
        cout << "加入辅料" << endl;
    }
};

void test01() {
    Tea a;
    a.make();
    cout << endl;
    Coffee b;
    b.make();
}


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

策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们还可以相互替换。策略模式让算法独立于使用他的客户而独立变化。

代码示例

#include <iostream>

using namespace std;

// 抽象武器策略
class WeaponStrategy {
public:
    virtual void UseWeapon() = 0;
};

class Knife : public WeaponStrategy {
public:
    void UseWeapon() override {
        cout << "使用了小刀" << endl;
    }
};

class Ak : public WeaponStrategy {
public:
    void UseWeapon() override {
        cout << "使用了AK" << endl;
    }
};

class Character {
public:
    void setWeapon(WeaponStrategy* Weapon) {
        this->pWeapon = Weapon;
    }

    void ThrowWeapon() {
        this->pWeapon->UseWeapon();
    }

    WeaponStrategy* pWeapon;
};

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

    // 武器策略
    WeaponStrategy* knife = new Knife;
    WeaponStrategy* ak = new Ak;

    character->setWeapon(knife);
    character->ThrowWeapon();

    character->setWeapon(ak);
    character->ThrowWeapon();

    delete character;
    delete knife;
    delete ak;
}

int main() {
    test01();

    return 0;
}

命令模式

将一个请求封装为一个对象, 从而可以用不同的请求对客户进行参数化。

好处:

  1. 命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
  2. 可以实现函数的延时处理。
#include <unistd.h>
#include <iostream>
#include <queue>

using namespace std;

// 协议处理
class HandleClientProtocal {
public:
    // 处理金币
    void addMoney() {
        cout << "给玩家增加金币!" << endl;
    }

    // 处理钻石
    void addDiamond() {
        cout << "给玩家增加钻石! " << endl;
    }

    // 处理装备
    void addEquipment() {
        cout << "给玩家穿装备! " << endl;
    }

    // 处理玩家升级
    void addLevel() {
        cout << "玩家升级了!" << endl;
    }
};

// 命令接口
class AbstractCommond {
public:
    virtual void handle() = 0;
};

class AddMoneyCommand : public AbstractCommond {
public:
    AddMoneyCommand(HandleClientProtocal* protocal) {
        this->pProtocal = protocal;
    }

    void handle() override {
        this->pProtocal->addMoney();
    }

    HandleClientProtocal* pProtocal;
};

class AddDiamondCommand : public AbstractCommond {
public:
    AddDiamondCommand(HandleClientProtocal* protocal) {
        this->pProtocal = protocal;
    }

    void handle() override {
        this->pProtocal->addDiamond();
    }

    HandleClientProtocal* pProtocal;
};

class AddEquipmentCommand : public AbstractCommond {
public:
    AddEquipmentCommand(HandleClientProtocal* protocal) {
        this->pProtocal = protocal;
    }

    void handle() override {
        this->pProtocal->addEquipment();
    }

    HandleClientProtocal* pProtocal;
};

class AddLevelCommand : public AbstractCommond {
public:
    AddLevelCommand(HandleClientProtocal* protocal) {
        this->pProtocal = protocal;
    }

    void handle() override {
        this->pProtocal->addLevel();
    }

    HandleClientProtocal* pProtocal;
};

// 服务器程序
class server {
public:
    void addRequest(AbstractCommond* command) {
        mCommands.push(command);
    }

    void startHandle() {
        while (!mCommands.empty()) {
            auto command = mCommands.front();
            mCommands.pop();
            command->handle();
            sleep(1);
        }
    }

    queue<AbstractCommond*> mCommands;
};

void test01() {
    HandleClientProtocal* protocal = new HandleClientProtocal;
    // 客户端增加金币
    AbstractCommond* addmoney = new AddMoneyCommand(protocal);
    // 客户端增加钻石
    AbstractCommond* addDiamond = new AddDiamondCommand(protocal);
    // 客户端穿装备
    AbstractCommond* addEquipment = new AddEquipmentCommand(protocal);
    // 客户端增加金币
    AbstractCommond* addLevel = new AddLevelCommand(protocal);

    server* ser = new server;
    // 将客户端的请求发送到服务器中
    ser->addRequest(addmoney);
    ser->addRequest(addDiamond);
    ser->addRequest(addEquipment);
    ser->addRequest(addLevel);

    // 服务器开始处理请求
    ser->startHandle();
    delete ser;
    delete addmoney;
    delete addDiamond;
    delete addEquipment;
    delete addLevel;
}


int main() {
    test01();

    return 0;
}

观察者模式

用于建立一种对象与对象之前的依赖关系, 一个对象发生改变的时候将自动通知其他的对象,其他对象将相应做出反应。发生改变的对象称为观察目标, 被通知的对象称为观察者。

#include <iostream>
#include <list>

using namespace std;

// 抽象的英雄
class AbstractHero {
public:
	virtual void update() = 0;
};

class HeroA : public AbstractHero {
public:
	HeroA() {
		cout << "英雄A正在撸boss" << endl;
	}
	void update() override {
		cout << "英雄A停止撸" << endl;
	}
};

class HeroB : public AbstractHero {
public:
	HeroB() {
		cout << "英雄B正在撸boss" << endl;
	}
	void update() override {
		cout << "英雄B停止撸" << endl;
	}
};

class HeroC : public AbstractHero {
public:
	HeroC() {
		cout << "英雄C正在撸boss" << endl;
	}
	void update() override {
		cout << "英雄C停止撸" << endl;
	}
};

// 观察目标抽象
class AbstractBoss {
public:
	virtual void addHero(AbstractHero* hero) = 0;
	virtual void deleteHero(AbstractHero* hero) = 0;
	virtual void notify() = 0;	//通知观察者
};

class BossA : public AbstractBoss {
public:
	void addHero(AbstractHero* hero) override {
		pHeroList.push_back(hero);

	}

	void deleteHero(AbstractHero* hero) override {
		pHeroList.remove(hero);	//删除指定的人
	}

	void notify() override {
		for (auto i : pHeroList) {
			i->update();
		}
	}
private:
	list<AbstractHero*> pHeroList;
};

void test01() {
	// 创建观察者
	HeroA heroA;
	HeroB heroB;
	HeroC heroC;

	// 创建被观察者
	BossA boss;
	// 添加观察者
	boss.addHero(&heroA);
	boss.addHero(&heroB);
	boss.addHero(&heroC);

	boss.notify();
	cout << "heroC阵亡" << endl;
	boss.deleteHero(&heroC);
	boss.notify();

}


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

装饰器模式

又叫包装模式,通过对客户端透明的方式来扩展对象功能。是继承关系的一种替代。

可以动态地给一个类拓展功能

#include <iostream>

using namespace std;

class AbstractHero {
public:
    virtual void ShowStatus() = 0;
public:
    int mHp;
    int mMp;
    int mAt;
    int mDf;
};

class HeroA : public AbstractHero {
public:
    HeroA() {
        mHp = 0;
        mMp = 0;
        mAt = 0;
        mDf = 0;
    }

    void ShowStatus() override {
        cout << "血量" << mHp << endl;
        cout << "魔法" << mMp << endl;
        cout << "攻击" << mAt << endl;
        cout << "防御" << mDf << endl;
    }
};

// 英雄穿上装饰物
// 既有以前对象的功能, 又有新的对象的功能
class AbstractEquipment : public AbstractHero{
public:
    AbstractEquipment(AbstractHero* hero) {
        this->pHero = hero;
    }

    virtual void ShowStatus() {}

    AbstractHero* pHero;
};

// 狂徒
class KuangtuEuqipment : public AbstractEquipment {
public:
    // 继承基类
    KuangtuEuqipment(AbstractHero* hero) : AbstractEquipment(hero) {

    }

    // 增加额外的功能
    void addKuangtu() {
        cout << "英雄穿上了狂徒披头" << endl;
        this->mHp = this->pHero->mHp;
        this->mMp = this->pHero->mMp;
        this->mAt = this->pHero->mAt;
        this->mDf = this->pHero->mDf + 30;

        delete this->pHero;
    }

    virtual void ShowStatus() override {
        addKuangtu();
        cout << "血量" << mHp << endl;
        cout << "魔法" << mMp << endl;
        cout << "攻击" << mAt << endl;
        cout << "防御" << mDf << endl;
    }
};

// 刀
class knifeEquipment : public AbstractEquipment {
public:
    // 继承基类
    knifeEquipment(AbstractHero* hero) : AbstractEquipment(hero) {

    }

    // 增加额外的功能
    void addKnifr() {
        cout << "英雄拿起刀" << endl;
        this->mHp = this->pHero->mHp;
        this->mMp = this->pHero->mMp;
        this->mAt = this->pHero->mAt + 30;
        this->mDf = this->pHero->mDf;

        delete this->pHero;
    }

    virtual void ShowStatus() override {
        addKnifr();
        cout << "血量" << mHp << endl;
        cout << "魔法" << mMp << endl;
        cout << "攻击" << mAt << endl;
        cout << "防御" << mDf << endl;
    }
};

void test01() {
     AbstractHero* hero = new HeroA;
     hero->ShowStatus();

     cout << "----------" << endl;

     // 给裸奔的有英雄穿衣服
     hero = new KuangtuEuqipment(hero);

     hero->ShowStatus();

     cout << "-----------" << endl;
     hero = new knifeEquipment(hero);
     hero->ShowStatus();
};

int main() {
    test01();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值