本文通過運用設計模式比沒用設計模式的優勢在哪?
設計模式主要是要抓住穩定部分和易變部分,文章結尾會指出。
繼承方式新增代碼
#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
類,易變部分是它們的子類。
關鍵在於:修飾物(消音器)可以修飾不同的被修飾物(槍),需要組合關係來運行時決定;但被修飾的物體(帶消音器的槍)也需要與槍又相同的接口,所有需要繼承關係編譯時已經可以決定。