c++裝飾模式

本文通過運用設計模式比沒用設計模式的優勢在哪?
設計模式主要是要抓住穩定部分和易變部分,文章結尾會指出。

繼承方式新增代碼

#include <iostream>
using namespace std;

//吃雞遊戲有好多種槍,下面槍是原有代碼,前人寫好了。
//槍的抽象類
class Gun {
public:
    virtual void shoot() = 0;
    virtual ~Gun() {}
};

class M16 : public Gun {
public:
    void shoot() override {
        cout << "M16 射擊" << endl;
    }
};

class AK : public Gun {
public:
    void shoot() override {
        cout << "AK 射擊" << endl;
    }
};

class AWM : public Gun {
public:
    void shoot() override {
        cout << "AWM 射擊" << endl;
    }
};

//現在的爲槍增加消音器。
//改變源代碼即會使原有的代碼不穩定,也會使得Gun類變得越來越複雜,職責不單一,且和消音器耦合在一起。
//所以我們選擇繼承。下面也又修改代碼的案例。
class SilencerM16 : public M16 {
public:
    void shoot() override {
        silence();
        M16::shoot();
    }
private:
    void silence() {
        cout << "使得槍聲變小" << endl;
    }
};

class SilencerAK : public AK {
public:
    void shoot() override {
        silence();
        AK::shoot();
    }
private:
    void silence() {
        cout << "使得槍聲變小" << endl;
    }
};

class SilencerAWM : public AWM {
public:
    void shoot() override {
        silence();
        AWM::shoot();
    }
private:
    void silence() {
        cout << "使得槍聲變小" << endl;
    }
};

//需求有又要爲槍支增加瞄準鏡,且可以和消音器一起配代。
class ScopeSilencerAWM : public SilencerAWM {
public:
    void shoot() override {
        useScope();
        SilencerAWM::shoot();
    }

private:
    void useScope() {
        cout << "使用了瞄準鏡" << endl;
    }
};

//...我的天,太多了。
//如果需求又要增加彈夾和槍托又該如何。

int main()
{
    Gun *ak = new AK;
    ak->shoot();
    
    Gun *silencer_ak = new SilencerAK;
    silencer_ak->shoot();
    
    Gun *scope_silencer_awm = new ScopeSilencerAWM;
    scope_silencer_awm->shoot();
    
    delete(ak);
    delete(silencer_ak);
    delete(scope_silencer_awm);

    return 0;
}

直接修改源代碼

#include <iostream>
using namespace std;

//增加消音器
class Silencer {
public:
    void silence() {
        cout << "使得槍聲變小了" << endl;
    }
};

//第二次需要增加瞄準鏡
class Scope {
public:
    void scope() {
        cout << "瞄準鏡" << endl;
    }
};

class Gun {
public:
    Gun() : silencer(nullptr), scope(nullptr) {}    //第一次修改新增代碼,第二次修改改變代碼
    Gun(Silencer *silencer, Scope *scope) : silencer(silencer), scope(scope) {} //第一次修改新增代碼,第二次修改新增代碼

    virtual void shoot() = 0;

    void setSilencer(Silencer *silencer) {  //第一次修改新增代碼
        this->silencer = silencer;
    }

    void setScope(Scope *scope) {   //第二次修改新增代碼
        this->scope = scope;
    }

protected:
    Silencer *silencer; //第一次修改新增代碼
    Scope *scope;   //第二次修改新增代碼
};

class M16 : public Gun {
public:
    M16() : Gun(nullptr, nullptr) {}    //第一次修改增加代碼
    explicit M16(Silencer *silencer) : Gun(silencer, nullptr) {}   //第一次修改新增代碼,第二次修改改變代碼
    explicit M16(Scope *scope) : Gun(nullptr, scope) {}   //第二次修改新增代碼
    M16(Silencer *silencer, Scope *scope) : Gun(silencer, scope) {}   //第二次修改新增代碼
    void shoot() override {
        if (silencer) silencer->silence();    //第一次修改新增代碼
        if (scope) scope->scope();  //第二次修改新增代碼
        cout << "M16 射擊" << endl;
    }
};

class AK : public Gun {
public:
    AK() : Gun(nullptr, nullptr) {}    //第一次修改增加代碼
    explicit AK(Silencer *silencer) : Gun(silencer, nullptr) {}   //第一次修改新增代碼,第二次修改改變代碼
    explicit AK(Scope *scope) : Gun(nullptr, scope) {}   //第二次修改新增代碼
    AK(Silencer *silencer, Scope *scope) : Gun(silencer, scope) {}   //第二次修改新增代碼
    void shoot() override {
        if (silencer) silencer->silence();    //第一次修改新增代碼
        if (scope) scope->scope();  //第二次修改新增代碼
        cout << "AK 射擊" << endl;
    }
};

class AWM : public Gun {
public:
    AWM() : Gun(nullptr, nullptr) {}    //第一次修改增加代碼
    explicit AWM(Silencer *silencer) : Gun(silencer, nullptr) {}   //第一次修改新增代碼,第二次修改改變代碼
    explicit AWM(Scope *scope) : Gun(nullptr, scope) {}   //第二次修改新增代碼
    AWM(Silencer *silencer, Scope *scope) : Gun(silencer, scope) {}   //第二次修改新增代碼
    void shoot() override {
        if (silencer) silencer->silence();    //第一次修改新增代碼
        if (scope) scope->scope();  //第二次修改新增代碼
        cout << "AWM 射擊" << endl;
    }
};
//所有槍的shoot方法可以用模板方法優化以下。
//如果需求又要增加彈夾和槍托又該如何。

int main()
{
    auto *silencer = new Silencer;
    auto *ak = new AK(silencer);
    ak->shoot();

    auto *scope = new Scope;
    ak->setScope(scope);
    ak->shoot();

    //注意釋放順序,不要出現指針懸掛。
    delete(ak);
    delete(scope);
    delete(silencer);

    return 0;
}

用繼承組合模式修改代碼(修飾模式)

#include <iostream>
using namespace std;

class Gun {
public:
    virtual void shoot() = 0;
};

class M16 : public Gun {
public:
    void shoot() override {
        cout << "M16 射擊" << endl;
    }
};

class AK : public Gun {
public:
    void shoot() override {
        cout << "AK 射擊" << endl;
    }
};

class AWM : public Gun {
public:
    void shoot() override {
        cout << "AWM 射擊" << endl;
    }
};

//新增代碼
//帶裝備的槍抽象類
class DecorateGun : public Gun {
public:
    DecorateGun(Gun *gun) : gun(gun) {}

protected:
    Gun *gun;
};

//新增消音器
class SilencerGun : public DecorateGun {
public:
    SilencerGun(Gun *gun) : DecorateGun(gun) {}
    void shoot() override {
        silence();
        gun->shoot();
    }

private:
    void silence() {
        cout << "槍的聲音變小了" << endl;
    }
};

//新增瞄準鏡
class ScopeGun : public DecorateGun {
public:
    ScopeGun(Gun *gun) : DecorateGun(gun) {}
    void shoot() override {
        scope();
        gun->shoot();
    }

private:
    void scope() {
        cout << "裝上了瞄準鏡" << endl;
    }
};

//新增xxx,無需修改源代碼,直接新增一個類即可。

int main()
{
    auto *ak = new AK;
    ak->shoot();

    auto *silencer_ak = new SilencerGun(ak);
    silencer_ak->shoot();

    auto *scope_ak = new ScopeGun(silencer_ak);
    scope_ak->shoot();

    //注意釋放順序,不要出現指針懸掛。
    delete(scope_ak);
    delete(silencer_ak);
    delete(ak);
    return 0;
}

上面代碼已經完成了修飾模式的任務,還可以通過策略模式進一步優化,可以更換消音器的種類。

#include <iostream>
using namespace std;

class Gun {
public:
    virtual void shoot() = 0;
};

class M16 : public Gun {
public:
    void shoot() override {
        cout << "M16 射擊" << endl;
    }
};

class AK : public Gun {
public:
    void shoot() override {
        cout << "AK 射擊" << endl;
    }
};

class AWM : public Gun {
public:
    void shoot() override {
        cout << "AWM 射擊" << endl;
    }
};

//新增代碼
//帶裝備的槍抽象類
class DecorateGun : public Gun {
public:
    DecorateGun(Gun *gun) : gun(gun) {}

protected:
    Gun *gun;
};

//新增消音器
//消音器抽象類,策略模式優化。
class Silencer {
public:
    virtual void silence() {
        cout << "默認沒有安裝消音器" << endl;
    }
};

class Silencer1 : public Silencer {
public:
    void silence() override {
        cout << "槍的聲音變小了1" << endl;
    }
};

class Silencer2 : public Silencer {
public:
    void silence() override {
        cout << "槍的聲音變小了2" << endl;
    }
};

class SilencerGun : public DecorateGun {
public:
    SilencerGun(Gun *gun, Silencer *silencer) : DecorateGun(gun), silencer(silencer) {}
    void shoot() override {
        silencer->silence();
        gun->shoot();
    }

    void setSilencer(Silencer *silencer) {
        this->silencer = silencer;
    }

private:
    Silencer *silencer;
};

int main()
{
    Silencer no_silencer;

    auto *ak = new AK;
    ak->shoot();

    auto *silencer_ak = new SilencerGun(ak, &no_silencer);
    silencer_ak->shoot();

    auto siliencer = new Silencer1;
    silencer_ak->setSilencer(siliencer);
    silencer_ak->shoot();

    //注意釋放順序,不要出現指針懸掛。
    delete(silencer_ak);
    delete(siliencer);
    delete(ak);
    return 0;
}

修飾模式穩定部分是:Gun/Decorate類,易變部分是它們的子類。

關鍵在於:修飾物(消音器)可以修飾不同的被修飾物(槍),需要組合關係來運行時決定;但被修飾的物體(帶消音器的槍)也需要與槍又相同的接口,所有需要繼承關係編譯時已經可以決定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章