目录
一,设计模式
4,原型模式
饿汉式
懒汉式
懒汉式多线程
2,桥接模式
3,组合模式
4,装饰模式
5,外观模式
6,享元模式
7,代理模式
4,命令模式
9,状态模式
一,设计模式
设计模式(Design Pattern)是一套被反复使用的、多数人知晓的、经过分类编目的代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解。
二,23种设计模式的分类
根据其目的可分为创建型、结构型和行为型三种设计模式。
- 创建型模式主要用于创建对象。
- 结构型模式主要用于处理类或对象的组合。
- 行为型模式主要用于描述对类或对象怎样交互和怎样分配职责。
根据范围,即模式主要是用于处理类之间关系还是处理对象之间的关系,可分为类模式和对象模式两种:
- 类模式处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是属于静态的。
- 对象模式处理对象间的关系,这些关系在运行时时刻变化,更具动态性。
范围\目的 | 创建型模式 | 结构型模式 | 行为型模式 |
类模式 | 工厂方法模式 | (类)适配器模式 | 解释器模式 模板方法模式 |
对象模式 | 抽象工厂模式 建造者模式 原型模式 单例模式 | (对象)适配器模式 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式 | 职责链模式 命令模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 策略模式 访问者模式 |
三,创建型模式
1,工厂方法模式√
(1)简单工厂模式
简单工厂模式,不属于23种工厂模式。
C语言很难真正实现设计模式,以简单工厂模式为例,假设天神既可以创造猫,也可以创造狗:
#include <stdio.h>
typedef void(*OutFun)(void*);
typedef struct Cat
{
char *catName;
OutFun outFun;
}Cat;
typedef struct Dog
{
char *dogName;
OutFun outFun;
}Dog;
enum Animal
{
CAT,
DOG
};
void AnimalOutFun(void* p)
{
printf("I'm %s\n", (char *)*((char **)p));
}
void* GetAnimal(int type)
{
if (type == CAT)
{
Cat *cat = (Cat *)malloc(sizeof(Cat));
cat->catName = "cat1";
cat->outFun = AnimalOutFun;
return cat;
}
if (type == DOG)
{
Dog* dog = (Dog *)malloc(sizeof(Dog));
dog->dogName = "dog1";
dog->outFun = AnimalOutFun;
return dog;
}
return NULL;
}
int main()
{
Cat *cat = (Cat *)GetAnimal(CAT);
cat->outFun(cat);
Dog* dog = (Dog *)GetAnimal(DOG);
dog->outFun(dog);
return 0;
}
运行结果:
I'm cat1
I'm dog1
其中GetAnimal函数就是工厂方法。
正如这个代码一样,C语言实现设计模式会很复杂,而 cat->outFun(cat) 这种自己处理自己的代码更是满天飞。
用C++实现同样的功能,头文件:
class Animals
{
public:
virtual void OutFun() {};
};
class Cat :public Animals
{
public:
void OutFun();
};
class Dog :public Animals
{
public:
void OutFun();
};
class Factory
{
public:
static Animals* GetAnimal(int type);
};
cpp:
enum Animal
{
CAT,
DOG
};
void Cat::OutFun() {
cout << "I'm Cat\n";
}
void Dog::OutFun() {
cout << "I'm Dog\n";
}
Animals* Factory::GetAnimal(int type)
{
if (type == CAT)
{
Animals* res = new Cat();
return res;
}
if (type == DOG)
{
Animals* res = new Dog();
return res;
}
return NULL;
}
int main()
{
Animals *cat = Factory::GetAnimal(CAT);
cat->OutFun();
Animals* dog = Factory::GetAnimal(DOG);
dog->OutFun();
return 0;
}
简单工厂模式由抽象产品类(Animals)、具体产品类(Cat等)、工厂(GetAnimal)组成,抽象产品类和工厂类可以合并。
合并后的头文件:
class Animals
{
public:
virtual void OutFun() {};
static Animals* GetAnimal(int type);
};
class Cat :public Animals
{
public:
void OutFun();
};
class Dog :public Animals
{
public:
void OutFun();
};
cpp:
enum Animal
{
CAT,
DOG
};
void Cat::OutFun() {
cout << "I'm Cat\n";
}
void Dog::OutFun() {
cout << "I'm Dog\n";
}
Animals* Animals::GetAnimal(int type)
{
if (type == CAT)
{
Animals* res = new Cat();
return res;
}
if (type == DOG)
{
Animals* res = new Dog();
return res;
}
return NULL;
}
int main()
{
Animals *cat = Animals::GetAnimal(CAT);
cat->OutFun();
Animals* dog = Animals::GetAnimal(DOG);
dog->OutFun();
return 0;
}
因为工厂方法通常可以是静态函数,所以简单工厂模式也叫静态工厂模式。
(2)工厂方法模式
简单工厂模式中,每次新增产品都需要修改工厂,不符合开闭原则。
工厂方法模式由抽象产品类(Animals)、具体产品类(Cat等)、抽象工厂(Factory)、具体工厂(CatFactory等)组成
头文件:
class Animals
{
public:
virtual void OutFun() =0;
};
class Cat :public Animals
{
public:
void OutFun();
};
class Dog :public Animals
{
public:
void OutFun();
};
class Factory
{
public:
virtual Animals* GetAnimal() =0;
};
class CatFactory :public Factory
{
public:
Animals* GetAnimal();
};
class DogFactory :public Factory
{
public:
Animals* GetAnimal();
};
cpp:
void Cat::OutFun() {
cout << "I'm Cat\n";
}
void Dog::OutFun() {
cout << "I'm Dog\n";
}
Animals* CatFactory::GetAnimal()
{
Animals* res = new Cat();
return res;
}
Animals* DogFactory::GetAnimal()
{
Animals* res = new Dog();
return res;
}
int main()
{
CatFactory fac1;
Animals *cat = fac1.GetAnimal();
cat->OutFun();
DogFactory fac2;
Animals* dog = fac2.GetAnimal();
dog->OutFun();
return 0;
}
工厂方法模式也叫虚拟构造器模式、多态工厂模式。
新增产品不需要修改工厂,只需要新增具体工厂,符合开闭原则。
但缺点很明显,类太多了。
2,抽象工厂模式√
有很多交叉分类场景,比如天神既可以创造猫,也可以创造狗,但是创造的都是成年动物,而小猫和小狗是阎王安排投胎去的,那阎王也需要自己的工厂。
大猫大狗构成一个产品簇,小猫小狗构成一个产品簇,产品簇的分类和产品的分类构成交叉分类。
根据2个分类系能否用聚合形式表示,分为2种情况:
(1)可聚合形式
如果可以单独的表示产品簇的信息,然后用聚合的形式表示具体产品,那么具体工厂数是产品簇的分类数 + 产品的分类数。
class Animals
{
public:
virtual void OutFun() {};
static Animals* GetAnimal(int type);
};
class Cat :public Animals
{
public:
void OutFun() {
cout << "cat\n";
}
};
class Dog :public Animals
{
public:
void OutFun() {
cout << "dog\n";
}
};
enum Animal
{
CAT,
DOG
};
Animals* Animals::GetAnimal(int type)
{
if (type == CAT)
{
Animals* res = new Cat();
return res;
}
if (type == DOG)
{
Animals* res = new Dog();
return res;
}
return NULL;
}
class Size
{
public:
virtual void OutFun() {};
static Size* GetSize(int type);
};
class Big :public Size
{
public:
void OutFun() {
cout << "I'm big ";
}
};
class Small :public Size
{
public:
void OutFun() {
cout << "I'm small ";
}
};
enum Size_
{
BIG,
SMALL
};
Size* Size::GetSize(int type)
{
if (type == BIG)
{
Size* res = new Big();
return res;
}
if (type == SMALL)
{
Size* res = new Small();
return res;
}
return NULL;
}
class FinalAnimal {
public:
FinalAnimal(int animalType, int sizeType) {
animal = Animals::GetAnimal(animalType);
size = Size::GetSize(sizeType);
}
void OutFun() {
size->OutFun();
animal->OutFun();
}
private:
Animals* animal;
Size* size;
};
int main()
{
FinalAnimal(CAT, BIG).OutFun();
FinalAnimal(DOG, SMALL).OutFun();
return 0;
}
输出:
(2)不可聚合形式
如果不能单独的表示产品簇的信息,那么具体工厂数 = 产品簇的分类数 * 产品的分类数。
class Animals {
public:
virtual void OutFun() {};
static Animals* GetAnimal(int animalType, int sizeType);
};
class BigAnimals :public Animals
{
public:
virtual void OutFun() {};
static BigAnimals* GetAnimal(int type);
};
class BigCat :public BigAnimals
{
public:
void OutFun() {
cout << "I'm big cat\n";
}
};
class BigDog :public BigAnimals
{
public:
void OutFun() {
cout << "I'm big dog\n";
}
};
enum Animal
{
CAT,
DOG
};
BigAnimals* BigAnimals::GetAnimal(int type)
{
if (type == CAT)
{
BigAnimals* res = new BigCat();
return res;
}
if (type == DOG)
{
BigAnimals* res = new BigDog();
return res;
}
return NULL;
}
class SmallAnimals :public Animals
{
public:
virtual void OutFun() {};
static SmallAnimals* GetAnimal(int type);
};
class SmallCat :public SmallAnimals
{
public:
void OutFun() {
cout << "I'm small cat\n";
}
};
class SmallDog :public SmallAnimals
{
public:
void OutFun() {
cout << "I'm small dog\n";
}
};
SmallAnimals* SmallAnimals::GetAnimal(int type)
{
if (type == CAT)
{
SmallAnimals* res = new SmallCat();
return res;
}
if (type == DOG)
{
SmallAnimals* res = new SmallDog();
return res;
}
return NULL;
}
enum Size_
{
BIG,
SMALL
};
Animals* Animals::GetAnimal(int animalType, int sizeType) {
if (sizeType == BIG) return (Animals*)BigAnimals::GetAnimal(animalType);
if (sizeType == SMALL) return (Animals*)SmallAnimals::GetAnimal(animalType);
return NULL;
}
int main()
{
Animals::GetAnimal(CAT, BIG)->OutFun();
Animals::GetAnimal(DOG, SMALL)->OutFun();
return 0;
}
输出:
如果要新增产品簇(老狗和老猫),那么只需要新增一个OldAnimals类,新增一个GetAnimal方法即可。
如果要新增产品(大马和小马),那么每个产品簇都需要修改。
3,建造者模式
4,原型模式
5,单例模式√
四,结构型模式
1,适配器模式
(1)类适配器模式
(2)对象适配器模式
2,桥接模式
3,组合模式
4,装饰模式
5,外观模式
6,享元模式
7,代理模式
五,行为型模式
1,解释器模式
2,模板方法模式√
解释:
模板方法模式,就是父类规定了统一的流程,子类去实现流程每一步的细节。
场景一:
当我们教小孩穿衣服的时候,我们希望小孩知道,先穿上衣,再穿裤子,再穿鞋子,这个是固定的流程,和衣服的颜色无关,和裤子是运动裤还是牛仔裤也无关。
有了这个概念之后,再教孩子各种上衣怎么穿,各种裤子怎么穿,各种鞋子怎么穿,孩子的脑海中就会有知识图谱的概念了。
实现:
我们用父类规定穿衣服的流程,子类去实现各个步骤如何操作。
#include<iostream>
using namespace std;
class dress
{
virtual void dressCoat()=0;
virtual void dressPants()=0;
virtual void dressShoes()=0;
public:
void dressAll()
{
dressCoat();
dressPants();
dressShoes();
cout<<endl;
}
};
class dressRed:public dress
{
void dressCoat(){
cout<<"Red coat ";
}
void dressPants(){
cout<<"Red pants ";
}
void dressShoes(){
cout<<"Red shoes ";
}
};
class dressBlue:public dress
{
void dressCoat(){
cout<<"Blue coat ";
}
void dressPants(){
cout<<"Blue pants ";
}
void dressShoes(){
cout<<"Blue shoes ";
}
};
int main()
{
dressRed d;
d.dressAll();
dressBlue d2;
d2.dressAll();
return 0;
}
输出:
Red coat Red pants Red shoes
Blue coat Blue pants Blue shoes
C语言模拟:
C语言没有这种代码机制,可以用函数指针实现回调机制,实现类似的效果。
参考我的毕设作品:本科毕业设计
场景二:
如果各个子类的流程不完全相同,比如其中有一步有的子类不需要实现,那么我们可以把父类函数设为虚函数,提供一个空实现即可。
#include<iostream>
using namespace std;
class dress
{
virtual void dressCoat() {};
virtual void dressPants() {};
virtual void dressShoes() {};
public:
void dressAll()
{
dressCoat();
dressPants();
dressShoes();
cout << endl;
}
};
class dressRed :public dress
{
void dressCoat() {
cout << "Red coat ";
}
void dressPants() {
cout << "Red pants ";
}
void dressShoes() {
cout << "Red shoes ";
}
};
class dressBlue :public dress
{
void dressCoat() {
cout << "Blue coat ";
}
void dressPants() {
cout << "Blue pants ";
}
};
int main()
{
dressRed d;
d.dressAll();
dressBlue d2;
d2.dressAll();
return 0;
}
输出:
Red coat Red pants Red shoes
Blue coat Blue pants