设计模式六大原则
- 开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码。
- 单一职责原则
不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。
- 里氏替换原则
里氏代换原则(Liskov Substitution Principle LSP)中说,任何基类可以出现的地方,一定可以用其子类替换。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
- 依赖倒换原则
面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
- 接口隔离原则
每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
- 迪米特法则(最少知道原则)
一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
- 合成复用原则
尽量首先使用合成/聚合的方式,而不是使用继承。
创建型模式
- 工厂模式
简单工厂 工厂方法模式 抽象工厂模式
有一家物流公司,可以提供不同类型的运输工具,进行物流运输。客户要走陆运,就从公司里要一辆卡车,要海运就从公司要一艘船
enum VTYPE {SHIP, TRUCK};
class Vehicles
{
public:
virtual void Show() = 0;
};
//陆运
class Truck: public Vehicles
{
public:
void Show() { cout<<"This is a truck"<<endl; }
};
//海运
class Ship: public Vehicles
{
public:
void Show() { cout<<"This is a ship"<<endl; }
};
//唯一的工厂,可以生产不同的载具,在内部判断
class Factory
{
public:
Vehicles* CreateVehicles(enum VTYPE Vtype)
{
if(Vtype == SHIP) //工厂内部判断
return new Ship(); //生产船
else if(Vtype == TRUCK)
return new Truck(); //生产卡车
else
return nullptr;
}
};
- 要增加一个新的载具类型,需要修改工厂类,违背开闭原则
所以出现了工厂方法,不再通过修改工厂实现,而实创建新的工厂
- 模式定义
- 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式使得一个类的实例化延迟到子类完成。
#include <iostream>
using namespace std;
class Vehicles
{
public:
virtual void Show() = 0;
};
//陆运
class Truck : public Vehicles
{
public:
void Show() { cout << "This is a truck" << endl; }
};
//海运
class Ship : public Vehicles
{
public:
void Show() { cout << "This is a ship" << endl; }
};
class Factory
{
public:
virtual Vehicles* CreateVehicle() = 0;
};
//生产船的工厂
class FactoryShip : public Factory
{
public:
Ship* CreateVehicle() { return new Ship(); }
};
//生产卡车的工厂
class FactoryTruck : public Factory
{
public:
Truck* CreateVehicle() { return new Truck(); }
};
int main()
{
FactoryTruck *m_TruckFactory = new FactoryTruck();
FactoryShip *m_ShipFactory = new FactoryShip();
Vehicles* m_Truck = m_TruckFactory->CreateVehicle();
m_Truck->Show();
Vehicles* m_Ship = m_ShipFactory->CreateVehicle();
m_Ship->Show();
return 0;
}
- 问题在于 每增加一种产品,就会增加一个工厂类
现在公司业务升级,提供了更大载荷的承运方案,需要生产不同规格的卡车、轮船
#include <iostream>
using namespace std;
class Vehicles
{
public:
virtual void Show() = 0;
};
//陆运
class Truck : public Vehicles
{
public:
void Show() { cout << "This is a truck" << endl; }
};
//海运
class Ship : public Vehicles
{
public:
void Show() { cout << "This is a ship" << endl; }
};
//大型载具
class BigVehicles
{
public:
virtual void Show() = 0;
};
class BigTruck : public BigVehicles
{
public:
void Show() { cout << "This is a BIG truck" << endl; }
};
class BigShip : public BigVehicles
{
public:
void Show() { cout << "This is a BIG ship" << endl; }
};
//工厂
class Factory
{
public:
virtual Vehicles* CreateVehicles() = 0;
virtual BigVehicles* CreateBigVehicles() = 0;
};
//卡车工厂,生产大型、小型卡车
class FactoryTruck :public Factory
{
public:
Vehicles* CreateVehicles() { return new Truck(); }
BigVehicles* CreateBigVehicles() { return new BigTruck(); }
};
//船工厂,生产大型、小型船
class FactoryShip : public Factory
{
public:
Vehicles* CreateVehicles() { return new Ship(); }
BigVehicles* CreateBigVehicles() { return new BigShip(); }
};
int main()
{
FactoryTruck* m_TruckFactory = new FactoryTruck();
FactoryShip* m_ShipFactory = new FactoryShip();
Vehicles* m_Truck = m_TruckFactory->CreateVehicles();
Vehicles* m_Ship = m_ShipFactory->CreateVehicles();
BigVehicles* m_BigTruck = m_TruckFactory->CreateBigVehicles();
BigVehicles* m_BigShip = m_ShipFactory->CreateBigVehicles();
m_Ship->Show();
m_Truck->Show();
m_BigShip->Show();
m_BigTruck->Show();
return 0;
}
-
如果需要拓展抽象工厂里面的方法会比较麻烦,因为我们必须修改抽象类以及添加对应的产品,这样修改量比较大,但是每种产品之间相互解耦。
- 建造者模式
- 模式意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
特点: 用于对复杂对象的构造、初始化,与工厂模式不同的是,建造者的目的在于把复杂构造过程从不同对象展现中抽离出来,使得同样的构造工序可以展现出不同的产品对象。
-
适用场景
-
相同的方法,不同的执行顺序,产生不同的结果时,可以采用建造者模式。
-
多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
-
产品类非常复杂,或者产品类中的方法调用顺序不同产生了不同的效能,这个时候使用建造者模式。
都builder了,就举一个盖房子的例子
比如盖一栋房子需要 地基 墙体 房顶三部分组成
我们创建建筑物类Building
抽象出建造方法类Builder
创建一个HouseBuilder用来描述具体各部件的构造方式
最后用Director类对构造流程进行管理,通过它选择不同的构造方式,并明确具体的构造流程,最终得到我们的复杂产品
#include <iostream>
#include <vector>
using namespace std;
class Building
{
private:
vector<string> BuildingComponents;
public:
void SetBasement(string basement) {
BuildingComponents.push_back(basement);
}
void SetWall(string wall) {
BuildingComponents.push_back(wall);
}
void SetRoof(string roof) {
BuildingComponents.push_back(roof);
}
void PrintBuilding() {
for (int i = BuildingComponents.size() - 1; i >= 0; i--) {
cout << BuildingComponents[i] << endl;
}
return;
}
};
class Builder
{
public:
virtual void BuildBasement() = 0;
virtual void BuildWall() = 0;
virtual void BuildRoof() = 0;
virtual void GetBuilding() = 0;
};
class HouseBuilder : public Builder
{
private:
Building house;
public:
void BuildBasement() {
house.SetBasement("这里是house地基");
}
void BuildWall() {
house.SetWall("这里是house墙壁");
}
void BuildRoof() {
house.SetRoof(" house房顶! ");
}
void GetBuilding() {
house.PrintBuilding();
}
};
class Director
{
private:
Builder* m_pBuilder;
public:
Director(Builder* builder) { m_pBuilder = builder; }
void Create() {
m_pBuilder->BuildBasement();
m_pBuilder->BuildWall();
m_pBuilder->BuildWall();
m_pBuilder->BuildWall();
m_pBuilder->BuildWall();
m_pBuilder->BuildRoof();
m_pBuilder->GetBuilding();
}
};
int main()
{
HouseBuilder ahouse;
Director director(&ahouse);
director.Create();
return 0;
}
- 原型模式
- 模式意图
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
特点:
- 性能较好,原型模式是内存二进制流的复制,会比直接new一个对象性能较好
- 因为是直接复制,所以绕开了构造函数,这是优点也是缺点,要看实际使用场景
#include <iostream>
using namespace std;
//具体的实现类
class Sheep
{
public:
Sheep(int id, string name) :m_id(id), m_name(name)
{
cout << "new Sheep Comes" << endl;
}
//关键代码拷贝构造函数
Sheep(const Sheep& obj)
{
this->m_id = obj.m_id;
this->m_name = obj.m_name;
}
//关键代码克隆函数,返回return new Sheep(*this)
Sheep* clone()
{
return new Sheep(*this);
}
void show()
{
cout << "id :" << m_id << endl;
cout << "name:" << m_name.data() << endl;
cout << "Sheep id address:" << &m_id << endl;
cout << "Sheep name address:" << &m_name << endl;
}
private:
int m_id;
string m_name;
};
int main()
{
Sheep* s1 = new Sheep(9, "肖恩");
s1->show();
Sheep* s2 = s1->clone();
s2->show();
return 0;
}