本文通过运用设计模式比没用设计模式的优势在哪?
设计模式主要是要抓住稳定部分和易变部分,文章结尾会指出。
继承方式新增代码
#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
类,易变部分是它们的子类。
关键在于:修饰物(消音器)可以修饰不同的被修饰物(枪),需要组合关系来运行时决定;但被修饰的物体(带消音器的枪)也需要与枪又相同的接口,所有需要继承关系编译时已经可以决定。