一、总则
- 单一职责原则:每个类只做一件事,确保引起类变化的原因只有一个;
- 开闭原则:对扩展开放,对修改关闭。要增加功能,通过增加代码实现,而不是修改原代码;
- 里氏代换原则(LSP):抽象类出现的地方,都可以用他子类代替;
- 依赖倒转原则:依赖抽象而不是具体
- 接口隔离原则:一个接口干一件事;
- 合成复用原则:继承会使父类可能影响子类,因此优先用组合;
- 迪米特原则(最少知识原则):一个类对象尽可能少的了解其他类,中介
二、开闭原则
考虑这样的场景:
要设计一个计算器类,要实现加法减法运算,经过一段时间开发之后,任务完成;
现在要新增一个乘法运算,若使用传统的开发方法,就需要修改该计算器类的代码,这不符合开闭原则;
可以先定义一个抽象计算器类,再新建加法计算器类继承于他,减法计算器类继承于他,乘法法计算器类继承于他,如果要加其他功能的话,还可以继续新建类继承于他。
#include <iostream>
using namespace std;
//抽象计算器类
class AbstractCaculator
{
public:
virtual void setOperateNumber(int a, int b) {};
virtual int getResult()=0;
};
//加法计算机类,只负责加法
class PlusCaculator :public AbstractCaculator
{
public:
virtual void setOperateNumber(int a, int b) {
this->ma = a;
this->mb = b;
}
virtual int getResult() {
return ma + mb;
}
private:
int ma;
int mb;
};
//减法计算机类,只负责减法
class MinCaculator :public AbstractCaculator
{
public:
virtual void setOperateNumber(int a, int b) {
this->ma = a;
this->mb = b;
}
virtual int getResult() {
return ma - mb;
}
private:
int ma;
int mb;
};
//如果要增加其他运算,只需要继续增加子类
int main()
{
AbstractCaculator* Caculate = new PlusCaculator;
Caculate->setOperateNumber(10, 20);
cout << Caculate->getResult() << endl;
delete Caculate;
Caculate = new MinCaculator;
Caculate->setOperateNumber(10, 20);
cout << Caculate->getResult() << endl;
delete Caculate;
}
三、迪米特原则
考虑这样的场景:
现在有楼盘A(高质量),楼盘B(低质量),我要买一套高质量的楼盘,这个设计逻辑该如何实现:
传统方法:定义class A,class B,再在函数中挨个创建AB的实例,挨个判断他们的质量;
但这不符合迪米特原则,即我不需要了解他们是怎么样创建、判断的,我只需要一个高质量的楼盘。
根据迪米特原则:先创建一个抽象类楼盘,再创建class A继承于该抽象楼盘,创建class B继承于该抽象楼盘,再创建一个中介类,创建和判断的逻辑由中介完成,中介接收“高质量”或“低质量”,返回楼盘即可。
#include <iostream>
#include<string>
#include<vector>
using namespace std;
//抽象楼盘
class AbstractBuilding
{
public:
virtual void sale() {};
virtual string getQuality()=0;
};
//楼盘A 高质量
class BuildingA :public AbstractBuilding
{
public:
BuildingA(){
this->mQuality = "高质量";
}
virtual void sale() {
cout << "楼盘A已被售卖!" << mQuality << endl;
};
virtual string getQuality() {
return mQuality;
};
public:
string mQuality;
};
//楼盘B 低质量
class BuildingB :public AbstractBuilding
{
public:
BuildingB() {
this->mQuality = "低质量";
}
virtual void sale() {
cout << "楼盘B已被售卖!" << mQuality << endl;
};
virtual string getQuality() {
return mQuality;
};
public:
string mQuality;
};
//中介类
class MidClass
{
public:
MidClass()
{
//创建每一个楼盘类
AbstractBuilding* buliding = new BuildingA;
this->mallBuildings.push_back(buliding);
buliding = new BuildingB;
this->mallBuildings.push_back(buliding);
}
~MidClass()
{
for (vector<AbstractBuilding*>::iterator it = mallBuildings.begin(); it != mallBuildings.end(); it++)
{
if (*it != NULL)
delete *it;
}
}
AbstractBuilding* findMyBuilding(string quality)
{
for (vector<AbstractBuilding*>::iterator it = mallBuildings.begin(); it != mallBuildings.end(); it++)
{
if ((*it)->getQuality() == quality)
{
return *it;
}
}
return NULL;
}
public:
vector<AbstractBuilding*> mallBuildings;
};
int main()
{
//任务:要找一个高质量的楼盘
//传统方法 判断每一个楼盘类
AbstractBuilding* buliding = new BuildingA;
if (buliding->getQuality() == "高质量")
{
buliding->sale();
}
delete buliding;
buliding = new BuildingB;
if (buliding->getQuality() == "高质量")
{
buliding->sale();
}
delete buliding;
//中介模式
MidClass *mediator = new MidClass;
buliding = mediator->findMyBuilding("高质量");
buliding->sale();
}
四、合成复用原则
考虑一个问题,在游戏中,要执行 人开车 这个逻辑,需要什么?
需要对象人,对象车,以及一个开车函数。可以通过继承或者组合来实现,优先使用组合,即在一个类里面嵌入另一个类对象
#include <iostream>
using namespace std;
//抽象车
class AbstractCar
{
public:
virtual void run() {};
};
//宝马
class BwmCar:public AbstractCar
{
public:
virtual void run() {
cout << "宝马启动!" << endl;
};
};
//大众
class DazhongCar :public AbstractCar
{
public:
virtual void run() {
cout << "大众启动!" << endl;
};
};
//抽象人
class AbstractPerson
{
public:
virtual void setCar(AbstractCar* car) {};
virtual void douFeng() {};
public:
AbstractCar* car;
};
//人A
class PersonA :public AbstractPerson
{
public:
virtual void setCar(AbstractCar* car) {
this->car = car;
};
virtual void douFeng() {
car->run();
};
public:
AbstractCar* car;
};
int main()
{
AbstractPerson* A = new PersonA;
A->setCar(new BwmCar);
A->douFeng();
A->setCar(new DazhongCar);
A->douFeng();
}