一、设计模式的三原则:
-
面向接口编程,而非实现;
-
多用组合,少用继承;
-
高内聚、低耦合;
二、设计模式的六大原则
总原则:开闭原则(Open Close Principle)开闭原则就是说对扩展开放,对修改关闭。
使用设计模式的目的:可重用性、易理解性、保证代码可靠性。
1、单一职责原则
不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责
2、里氏替换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。里氏代换原则是对“开-闭”原则的补充。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
5、迪米特法则(最少知道原则)(Demeter Principle)
就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
6、合成复用原则(Composite Reuse Principle)
原则是尽量首先使用合成/聚合的方式,而不是使用继承。
C++语言将数据成员中包含对象成员的类称为组合类,而将数据成员中包含对象指针的类称为聚合类。聚合类是一种特殊形式的组合类。
聚合类和组合类的区别:
1)组合类的对象成员是独立创建的,聚合类对象只包含指向对象成员的指针。
2)聚合类对象可以共用对象成员。
一、设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
1、工厂方法模式
创建一个基类和几个继承基类的子类,创建一个工厂类,工厂类中定义一个成员函数,通过成员函数的参数值不同,让基类指针通过不同的参数值构建不同的子类。
// 简单工厂
class SimpleFactory
{
public:
// 获取产品
Prodect* getProdect(PRODECT_TYPE type) {
switch (type)
{
case APPLE:
prodect = new AppleProdect(5);
break;
case BANANA:
prodect = new BananaProdect(2);
break;
case PEAR:
prodect = new PearProdect(3);
break;
default:
cout << "无该产品。" << endl;
break;
}
return prodect;
}
private:
Prodect* prodect = nullptr;
};
2、抽象工厂模式
核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
//抽象产品
class Product
{public:virtual void show() = 0;};
//抽象产品族1 生产键盘
class KeyBoard :public Product {};
//具体产品
class LogiKeyBoard :public KeyBoard
{void show() {}};
class RazerKeyBoard :public KeyBoard
{void show(){}};
//抽象产品族2 除了生产键盘之外可以生产鼠标
class Mouse :public Product {};
class LogiMouse :public Mouse
{void show(){}};
class RazerMouse :public Mouse
{void show() {}}
//抽象工厂
class Factory
{
public:
//创建一个键盘
virtual KeyBoard* CreateKeyBoard() = 0;
//创建一个鼠标
virtual Mouse* CreateMouse() = 0;
};
//具体工厂 罗技工厂提供罗技键盘、罗技鼠标
class LogiFactory :public Factory
{
KeyBoard* CreateKeyBoard()
{
return new LogiKeyBoard;
}
Mouse* CreateMouse()
{
return new LogiMouse;
}
};
//雷蛇工厂提供雷蛇键盘、雷蛇鼠标
class RazerFactory :public Factory
{
KeyBoard* CreateKeyBoard()
{
return new RazerKeyBoard;
}
Mouse* CreateMouse()
{
return new RazerMouse;
}
};
int main()
{
//首先需要一个工厂
Factory* factory = new LogiFactory;
KeyBoard* keyBoard = factory->CreateKeyBoard();
Mouse* mouse = factory->CreateMouse();
keyBoard->show();
mouse->show();
//释放后做第二次测试
delete factory;
delete keyBoard;
delete mouse;
//雷蛇工厂只生产雷蛇产品
factory = new RazerFactory;
keyBoard = factory->CreateKeyBoard();
mouse = factory->CreateMouse();
keyBoard->show();
mouse->show();
delete factory;
delete keyBoard;
delete mouse;
factory = nullptr;
keyBoard = nullptr;
mouse = nullptr;
return 0;
}
3、单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。
定义一个单例类:
- 私有化它的构造函数,以防止外界创建单例类的对象;
- 使用类的私有静态指针变量指向类的唯一实例;
- 使用一个公有的静态方法获取该实例
懒汉版(Lazy Singleton)
单例实例在第一次被使用时才进行初始化,这叫做延迟初始化。
- 使用智能指针
- 使用静态的嵌套类对象
对于第二种解决方法,代码如下:
// version 1.0
class Singleton
{
private:
static Singleton* instance;
private:
Singleton() {};
~Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton* getInstance()
{
if(instance == NULL)
instance = new Singleton();
return instance;
}
};
// init static member
Singleton* Singleton::instance = NULL;
**问题1:**Lazy Singleton存在内存泄露的问题,有两种解决方法:
// version 1.1
class Singleton
{
private:
static Singleton* instance;
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
class Deletor {
public:
~Deletor() {
if(Singleton::instance != NULL)
delete Singleton::instance;
}
};
static Deletor deletor;
public:
static Singleton* getInstance() {
if(instance == NULL) {
instance = new Singleton();
}
return instance;
}
};
// init static member
Singleton* Singleton::instance = NULL;
多个线程同时懒汉版单列模式使用为了保证线程安全
方法一:
mutex mtx; //创建互斥锁对象
static Singleton* getInstance() {
if(instance == NULL) {
mtx.lock();
if(instance == NULL) {
instance = new Singleton();
}
mtx.unlock(mutx);
}
return instance;
}
方法二:
// version 1.2
class Singleton
{
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};
饿汉模式
// version 1.3
class Singleton
{
private:
static Singleton instance;
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance() {
return instance;
}
}
// initialize defaultly
Singleton Singleton::instance;
4、建造者模式
将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
内容可以是不同的,但是组合成的过程是相同的。
#include <string>
using namespace std;
typedef string Graphics;
typedef string Pen;
class PersonBuilder{
public:
virtual void buildHead(){}
virtual void buildBody(){}
virtual void buildArmLeft(){}
virtual void buildArmRight(){}
virtual void buildLegLeft(){}
virtual void buildLegRight(){}
PersonBuilder(Graphics g, Pen p);
virtual ~PersonBuilder();
private:
Graphics *g;
Pen *p;
};
class PersonThinBuilder : public PersonBuilder{
public:
PersonThinBuilder(Graphics g, Pen p);
void buildHead();
void buildBody();
void buildArmLeft();
void buildArmRight();
void buildLegLeft();
void buildLegRight();
};
class PersonFatBuilder : public PersonBuilder{
public:
PersonFatBuilder(Graphics g, Pen p);
void buildHead();
void buildBody();
void buildArmLeft();
void buildArmRight();
void buildLegLeft();
void buildLegRight();
};
class PersonDirector{
public:
PersonDirector(PersonBuilder *pb);
void createPersion();
private:
PersonBuilder *pb;
};
PersonDirector::PersonDirector(PersonBuilder *pb)
{
this->pb = pb;
}
void PersonDirector::createPersion()
{
pb->buildBody();
pb->buildHead();
pb->buildArmLeft();
pb->buildArmRight();
pb->buildLegLeft();
pb->buildLegRight();
}
int main(int *argc, int *argv){
PersonThinBuilder *pT = new PersonThinBuilder("画", "笔");
PersonDirector *pD = new PersonDirector(pT);
pD->createPersion();
delete pT;
delete pD;
cout << "------------ 分 割 线 ------------" << endl;
PersonFatBuilder *pF = new PersonFatBuilder("写", "黑笔");
PersonDirector *pD2 = new PersonDirector(pF);
pD2->createPersion();
delete pF;
delete pD2;
getchar();
return 0;
}
5、原型模式
通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象。
原型模式的实质就是实现对于原型的拷贝。主要是通过拷贝构造函数来实现
#include <iostream>
using namespace std;
class Monster{
public:
Monster(int m_hp) : hp(m_hp) {
cout << "战斗!" << endl;
}
virtual ~Monster() {}
virtual Monster* clone() = 0;
protected:
int hp;
};
class ShiLaimu : public Monster {
public:
ShiLaimu(int m_hp) : Monster(m_hp) {
}
ShiLaimu(const ShiLaimu& slm) : Monster(slm)//拷贝构造
{
this->hp = slm->hp;
}
virtual Monster* clone() {
return new ShiLaimu(*this);
}
};
void FenLie(Monster* pMonster) {
Monster* m_Monster = pMonster->clone();
/* 业务逻辑 */
delete m_Monster;
}
int main() {
Monster* slm = new ShiLaimu(100, 50, 50);
Monster* slm1 = slm->clone();
delete slm;
delete slm1;
return 0;
}