23种设计模式

目录

一,设计模式

二,23种设计模式的分类

三,创建型模式

1,工厂方法模式

(1)简单工厂模式

(2)工厂方法模式

2,抽象工厂模式

(1)可聚合形式

(2)不可聚合形式

3,建造者模式

4,原型模式

5,单例模式

(1) 饿汉式(线程安全)

(2)懒汉式

(3)懒汉式的多线程安全写法

(4)单例模板

四,结构型模式

1,适配器模式

2,桥接模式

3,组合模式

4,装饰模式

5,外观模式

6,享元模式

7,代理模式

五,行为型模式

1,解释器模式

2,模板方法模式

3,职责链模式

4,命令模式

5,迭代器模式

6,中介者模式

7,备忘录模式

8,观察者模式

9,状态模式

10,策略模式

11,访问者模式


一,设计模式

设计模式(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,建造者模式

建造者模式是用来解决建造复杂对象的问题。

复杂对象:

class Head
{
public:
	void set(string color, int weight){}
private:
	string color;
	int weight;
};
class Hand
{
public:
	void set(string color, int weight) {}
private:
	string color;
	int weight;
};

class Human
{
public:
	void setHead(string color, int weight)
	{
		head.set(color, weight);
	}
	void setHand(string color, int weight)
	{
		hand.set(color, weight);
	}
private:
	Head head;
	Hand hand;
};

建造基类:

class Builder
{
public:
	Builder()
	{
		human = new Human();
	}
	Human* get()
	{
		return human;
	}
	virtual void setHead() {}
	virtual void setHand() {}
protected:
	Human* human;
};

建造子类:

class ManBuilder:public Builder
{
	void setHead()
	{
		human->setHead("yellow", 10);
	}
	void setHand()
	{
		human->setHand("yellow", 8);
	}
};
class WomanBuilder :public Builder
{
	void setHead()
	{
		human->setHead("white", 9);
	}
	void setHand()
	{
		human->setHand("white", 7);
	}
};

4,原型模式

原型模式就是抽象类提供clone函数,具体类实现具体的clone函数。

代码:

class Person
{
public:
	virtual Person* clone() 
	{
		return new Person(); 
	}
	void show()
	{
		cout << "id=" << id << endl;
		cout << "name=" << name << endl;
	}
protected:
	int id = 0;
	string name;
};

class Student :public Person
{
public:
	Student(string name)
	{
		this->name = name;
		this->id = 0;
	}
	Student* clone()
	{
		Student* s = new Student(this->name);
		s->id = this->id + 1;
		return s;
	}
};

int main()
{
	Person* p1 = new Student("zsan");
	p1->show();
	Person* p2 = p1->clone();
	p2->show();
	return 0;
}

5,单例模式

单例模式是保证类只有一个实例的模式,非常实用。

(1) 饿汉式(线程安全)

恶汉式采用的是static成员,因为进程初始化时就分配好了,所以叫恶汉式。

第一种写法(引用):

class SingleA {
public:
    static SingleA& GetSingleA() {
        return s;
    }
    static SingleA s;
private:
    SingleA(const SingleA&) = delete;
    SingleA(SingleA&&) = delete;
    SingleA& operator=(const SingleA&) = delete;
    SingleA& operator=(SingleA&&) = delete;
    SingleA() = default;
    ~SingleA() = default;
};
SingleA SingleA::s;

第二种写法(指针):

class SingleA {
public:
	static SingleA* GetSingleA() {
		return s;
	}
	static SingleA* s;
private:
	SingleA(const SingleA&) = delete;
	SingleA(SingleA&&) = delete;
	SingleA& operator=(const SingleA&) = delete;
	SingleA& operator=(SingleA&&) = delete;
	SingleA() = default;
	~SingleA() = default;
};
SingleA* SingleA::s = new SingleA();

(2)懒汉式

懒汉式到第一次申请实例的时候才会分配。

第一种写法(引用,推荐写法,线程安全):

class SingleA {
public:
    static SingleA& GetSingleA() {
        static SingleA s;
        return s;
    }
private:
    SingleA(const SingleA&) = delete;
    SingleA(SingleA&&) = delete;
    SingleA& operator=(const SingleA&) = delete;
    SingleA& operator=(SingleA&&) = delete;
    SingleA() = default;
    ~SingleA() = default;
};

第二种写法(指针):

class SingleA {
public:
    static SingleA* GetSingleA() {
        static SingleA* s = new SingleA();
        return s;
    }
private:
    SingleA(const SingleA&) = delete;
    SingleA(SingleA&&) = delete;
    SingleA& operator=(const SingleA&) = delete;
    SingleA& operator=(SingleA&&) = delete;
    SingleA() = default;
    ~SingleA() = default;
};

第三种写法(带判断的指针):

class SingleA {
public:
    static SingleA* GetSingleA() {
        if (!s) s = new SingleA();
        return s;
    }
    static SingleA* s;
private:
    SingleA(const SingleA&) = delete;
    SingleA(SingleA&&) = delete;
    SingleA& operator=(const SingleA&) = delete;
    SingleA& operator=(SingleA&&) = delete;
    SingleA() = default;
    ~SingleA() = default;
};
SingleA* SingleA::s;

ps:引用的方式也可以用这种带判断的懒汉式写法,只需要把(!s)改成对应的判断是否初始化的条件即可。

(3)懒汉式的多线程安全写法

上面的懒汉式写法,只有第一种是安全的,用new的方式的都是不安全的,但是可以通过加锁变成安全的。

第一种写法(多线程安全写法):

class SingleA {
public:
	static SingleA* GetSingleA() {
		Lock();
		if (!s) s = new SingleA();
		Unlock();
		return s;
	}
	static SingleA* s;
private:
	SingleA(const SingleA&) = delete;
	SingleA(SingleA&&) = delete;
	SingleA& operator=(const SingleA&) = delete;
	SingleA& operator=(SingleA&&) = delete;
	SingleA() = default;
	~SingleA() = default;
};
SingleA* SingleA::s;

第二种写法(多线程安全的double check写法):

class SingleA {
public:
	static SingleA* GetSingleA() {
		if (!s) {
			Lock();
			if (!s) s = new SingleA();
			Unlock();
		}
		return s;
	}
	static SingleA* s;
private:
	SingleA(const SingleA&) = delete;
	SingleA(SingleA&&) = delete;
	SingleA& operator=(const SingleA&) = delete;
	SingleA& operator=(SingleA&&) = delete;
	SingleA() = default;
	~SingleA() = default;
};
SingleA* SingleA::s;

采用double check可以减少锁的次数,减少性能消耗。

(4)单例模板

需要用到CRTP实现

template<typename T>
class SingleA {
public:
	static T& GetSingleA() {
		static T s;
		return s;
	}
protected:
	SingleA(const SingleA&) = delete;
	SingleA(SingleA&&) = delete;
	SingleA& operator=(const SingleA&) = delete;
	SingleA& operator=(SingleA&&) = delete;
	SingleA() = default;
	~SingleA() = default;
};

class A :public SingleA<A>
{
	friend class SingleA<A>;
public:
	int x;
private:
	A() = default;
};

父类的构造函数要声明为protected,子类还要声明父类为友元类。

四,结构型模式

1,适配器模式

适配器模式是把老的接口封装成新的接口。

(1)类适配器模式

类适配器模式是用新的类继承2个类。

如果老接口是具体类:

class A
{
public:
	void open() {};
	void show() {};
};
class C
{
public:
	virtual void openAndShow() {};
};
class NewA :public A, public C
{
public:
	void openAndShow()
	{
		open();
		show();
	}
};

如果老接口是抽象接口+具体实现类,那就不能用类适配器模式。

(2)对象适配器模式

对象适配器模式是新的类聚合老接口,继承目标类。

如果老接口是具体类:

class A
{
public:
	void open() {};
	void show() {};
};
class C
{
public:
	virtual void openAndShow() {};
};
class NewA :public C
{
public:
	NewA(A* p)
	{
		opt = p;
	}
	void openAndShow()
	{
		opt->open();
		opt->show();
	}
private:
	A* opt;
};

如果老接口是抽象接口+具体实现类,那就只能用对象适配器模式。

原接口AB和目标接口C:

class A
{
public:
	virtual void open() {};
	virtual void show() {};
};
class B :public A
{
public:
	void open() {};
	void show() {};
};
class C
{
public:
	virtual void openAndShow() {};
};
class NewB :public C
{
public:
	NewB(A* p)
	{
		opt = p;
	}
	void openAndShow()
	{
		opt->open();
		opt->show();
	}
private:
	A* opt;
};

2,桥接模式

桥接模式就是把包含2组信息的类拆分成2个类,通过聚合的形式桥接到一起。

这样,就只需要独立定义每一组信息的不同的类,而不需要交叉定义所有的类。

如红苹果、绿苹果、红桃子、绿桃子四个子类显得很冗余,再新增水果或颜色就更麻烦了,我们把信息拆分成水果类型和颜色2个类。

抽象颜色和具体颜色:

class Color
{
public:
	virtual void show()
	{
		cout << col;
	}
	virtual bool canEat() { return true; };
protected:
	string col;
};
class Red :public Color
{
public:
	Red()
	{
		col = "red";
	}
	bool canEat()
	{
		return true;
	}
};
class Green :public Color
{
public:
	Green()
	{
		col = "green";
	}
	bool canEat()
	{
		return false;
	}
};

承载简单逻辑:红的可以吃,绿的不能吃。

抽象水果和具体水果:

class Fruit
{
public:
	void show()
	{
		if (color->canEat())
		{
			howEat();
		}
		else {
			cout << "cannot eat\n";
		}
	}
	void setColor(Color* col)
	{
		color = col;
	}
protected:
	virtual void howEat() {};
private:
	Color* color;
};
class Apple :public Fruit
{
	void howEat()
	{
		cout << "eat directly\n";
	}
};
class Peach :public Fruit
{
	void howEat()
	{
		cout << "skin and eat\n";
	}
};

抽象水果类聚合抽象颜色类。

调用示例:

int main() 
{
	Apple ap;
	ap.setColor(new Red());
	ap.show();
	ap.setColor(new Green());
	ap.show();
	Peach pe;
	pe.setColor(new Red());
	pe.show();
	pe.setColor(new Green());
	pe.show();
}

输出:

eat directly
cannot eat
skin and eat
cannot eat

即4种水果的情况。

3,组合模式

组合模式就是把一些有相同处理的对象放到一起,形成树的结构,递归调用。

节点基类:

class Component
{
public:
	virtual void Run() {};
};

组合节点:

class Composite : public Component
{
public:
	void Add(Component* c)
	{
		v.push_back(c);
	}
	void Run()
	{
		cout << "Composite run.\n";
		for (auto &vi : v) {
			vi->Run();
		}
	}
private:
	vector<Component*>v;
};

叶子节点:

class A : public Component
{
public:
	void Run()
	{
		cout << "A run.\n";
	}
};
class B : public Component
{
public:
	void Run()
	{
		cout << "B run.\n";
	}
};

调用示例:

int main()
{
	Composite* s = new Composite();
	Component* a = new A();
	Component* b = new B();
	s->Add(a);
	s->Add(b);
	s->Run();
	return 0;
}

输出:

Composite run.
A run.
B run.

4,装饰模式

装饰模式就是通过额外的装饰类来给对象添加新的行为。

抽象基类和具体类:

class Phone
{
public:
	virtual void show() = 0;
};
class Andr :public Phone
{
public:
	void show()
	{
		cout << "\nAndroid";
	}
};
class Ipho :public Phone
{
public:
	void show()
	{
		cout << "\nIphone";
	}
};

抽象装饰和具体装饰:(抽象装饰要继承抽象基类)

class Decorator :public Phone
{
public:
	Decorator(Phone* p)
	{
		mphone = p;
	}
	void show()
	{
		mphone->show();
	}
protected:
	Phone* mphone;
};
class NameDecorator :public Decorator
{
	using Decorator::Decorator;
public:
	void setName(string name)
	{
		this->name = name;
	}
	void show()
	{
		mphone->show();
		cout << name;
	}
private:
	string name;
};
class IdDecorator :public Decorator
{
	using Decorator::Decorator;
public:
	void setId(int id)
	{
		this->id = id;
	}
	void show()
	{
		mphone->show();
		cout << id;
	}
private:
	int id;
};

调用示例:

int main() 
{
	Phone* p1 = new Andr();
	p1->show();
	Phone* p2 = new Ipho();
	p2->show();
	NameDecorator* p3 = new NameDecorator(p1);
	p3->setName(" Honor ");
	p3->show();
	IdDecorator* p4 = new IdDecorator(p3);
	p4->setId(13);
	p4->show();
}

输出:

Android
Iphone
Android Honor
Android Honor 13

5,外观模式

 

外观模式也叫门面模式,通过调用封装,使得对外的接口稳定且简洁。

class A
{
public:
	void run() {};
};
class B
{
public:
	void run() {};
};
class C
{
public:
	void run() {};
};

class Facade
{
public:
	Facade()
	{
		a = new A;
		b = new B;
		c = new C;
	}
	void fun1()
	{
		a->run();
		b->run();
	}
	void fun2()
	{
		c->run();
	}
private:
	A* a;
	B* b;
	C* c;
};

6,享元模式

享元模式就是利用共享技术存储大量小对象。

比如要存储大量字符串,对于重复的字符串可以合并。

字符串包装类:

class MyString
{
public:
	MyString(string s)
	{
		this->s = s;
	}
	bool operator< (MyString s) const
	{
		return this->s < s.s;
	}
	string GetData() const
	{
		return s;
	}
private:
	string s;
};

字符串集合类:

struct cmp
{
	bool operator()(MyString* m1, MyString* m2)const
	{
		return *m1 < *m2;
	}
};

class StringSet
{
public:
	MyString* GetMyString(string s)
	{
		MyString* ms = new MyString(s);
		auto it = se.find(ms);
		if (it == se.end()) {
			se.insert(ms);
			return ms;
		}
		return *it;
	}
	void Push(string s)
	{
		GetMyString(s);
	}
	int size()
	{
		return se.size();
	}
private:
	set < MyString*, cmp> se;
};

调用示例:

int main()
{
	StringSet s;
	s.Push("123");
	s.Push("123");
	MyString* it = s.GetMyString("123");
	cout << it->GetData() << endl;
	cout << s.size();
	return 0;
} 

输出:

123
1

7,代理模式

代理模式是用一个类的对象控制另外一个类的对象,2个类有相同的接口。

按照使用场景,可以分为若干种代理场景。

以虚拟代理为例:

虚拟代理是为了实现延迟加载,比如一个网页中有图片,加载网页时可以不加载图片,等到一定时机(比如滑动滚轮,图片进入视域范围)才加载。

抽象图片基类:

class ImageBase
{
public:
	ImageBase(string name) :fileName(name) {}
	virtual void show() {}
protected:
	string fileName;
};

图片类:

class Image :public ImageBase
{
public:
	Image(string name) : ImageBase(name) {}
	void show() {
		cout << "show image " << fileName;
	}
};

图片代理类:

class ImageProxy:public ImageBase
{
public:
	ImageProxy(string name) : ImageBase(name) {}
	void show() {
		if (!img)img = new Image(fileName);
		img->show();
	}
private:
	Image* img;
};

调用示例:

int main()
{
	ImageBase* img = new ImageProxy("123.png");
	img->show();
	return 0;
}

五,行为型模式

1,解释器模式

解释器模式也叫解析器模式,是把复杂的业务规则抽象成语法规则。

在这里插入图片描述

优点:把复杂抽象的逻辑,显式化成具体的表达式

缺点:小类太多,代码膨胀,性能也可能有影响。

以标准体重计算器为例:

数据:

class H
{
public:
	static int h;
	static void set(int h) {
		H::h = h;
	}
};
class W
{
public:
	static int w;
	static void set(int w) {
		W::w = w;
	}
};
int H::h = 0;
int W::w = 0;

纯数字表达式:

// 把字符串转化为整数
int atoi(const char *nptr, int radix) //copy from somebody
{
	while (isspace((int)(unsigned char)*nptr))  ++nptr;/* skip whitespace */
	int c = (int)(unsigned char)*nptr++;
	int sign = c;           /* save sign indication */
	if (c == '-' || c == '+')  c = (int)(unsigned char)*nptr++;    /* skip sign */
	int total = 0;
	while (isdigit(c)) {
		total = radix * total + (c - '0');     /* accumulate digit */
		c = (int)(unsigned char)*nptr++;    /* get next char */
	}
	if (sign == '-')   return -total;
	else  return total;   /* return result, negated if necessary */
}

class Data 
{
public:
	static int solve(string str) {
		if (str == "H")return H::h;
		if (str == "W")return W::w;
		return atoi(str.data(), 10);
	}
};

-和>组成的表达式:

class SubExp
{
public:
	static int solve(string str) {
		for (int i = str.size()-1; i > 0; i--) {
			if (str[i] != '-')continue;
			return SubExp::solve(str.substr(0, i)) - Data::solve(str.substr(i + 1, str.size() - i - 1));
		}
		return Data::solve(str);
	}
};
class GreaterExp
{
public:
	static int solve(string str) {
		for (int i = 0; i < str.size(); i++) {
			if (str[i] != '>')continue;
			return SubExp::solve(str.substr(0, i)) > SubExp::solve(str.substr(i + 1, str.size() - i - 1));
		}
		return SubExp::solve(str);
	}
};

对外接口:

int solve(string s)
{
	return GreaterExp::solve(s);
}

优先级最低的表达式,作为表达式的入口。

承载业务规则的表达式:

bool thinMan(int height, int weight)
{
	H::set(height);
	W::set(weight);
	return solve("H-105>W");
}
bool thinWoman(int height, int weight)
{
	H::set(height);
	W::set(weight);
	return solve("H-108>W");
}

调用示例:

int main()
{
	cout << thinMan(169, 67);
	cout << thinWoman(165, 55);
	cout << solve("3>2");
	cout << solve("10-2-3");
	return 0;
}

既支持计算常量表达式,也支持设定抽象表达式,往里传值。

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

CRTP + 模板方法模式

#include<iostream>
using namespace std;

template<typename T>
class dress
{
public:
	void dressAll()
	{
		T* p = sub();
		p->dressCoat();
		p->dressPants();
		p->dressShoes();
		cout << endl;
	}
protected:
	void dressShoes() {}
	T* sub() {
		return static_cast<T*>(this);
	}
};

class dressRed :public dress< dressRed>
{
public:
	void dressCoat() {
		cout << "Red coat ";
	}
	void dressPants() {
		cout << "Red pants ";
	}
	void dressShoes() {
		cout << "Red shoes ";
	}
};

class dressBlue :public dress<dressBlue>
{
public:
	void dressCoat() {
		cout << "Blue coat ";
	}
	void dressPants() {
		cout << "Blue pants ";
	}
};

int main()
{
	dressRed d;
	d.dressAll();
	dressBlue d2;
	d2.dressAll();
	return 0;
}

3,职责链模式

职责链模式就是一系列的处理过程依次执行,各部件可以自由的用链表的形式链接起来。

优点:降低了部件之间的耦合。

缺点:需要客户端进行组合链接,增加了客户端的复杂性。(从形式上可以任意组合链接,但从业务逻辑上可能有限制)

例一,抽象例子

我这里的例子比较简单,是无参的处理函数,实际上也可以把参数一直传递。

处理基类:

class Handle
{
public:
	virtual void Run() {};
	void SetNext(Handle* next)
	{
		this->next = next;
	}
protected:
	Handle* next = nullptr;
};

处理子类:

class HandleA : public Handle
{
public:
	void Run()
	{
		cout << "HandleA run.\n";
		if (next)next->Run();
	}
};
class HandleB : public Handle
{
public:
	void Run()
	{
		cout << "HandleB run.\n";
		if (next)next->Run();
	}
};
class HandleC : public Handle
{
public:
	void Run()
	{
		cout << "HandleC run.\n";
		if (next)next->Run();
	}
};

调用示例:

int main()
{
	Handle* a = new HandleA();
	Handle* b = new HandleB();
	Handle* c = new HandleC();
	a->SetNext(b);
	b->SetNext(c);
	a->Run();
    return 0;
}

输出:

HandleA run.
HandleB run.
HandleC run.

例二,告警例子

#include <iostream>
using namespace std;
class Responder {
public:
	virtual ~Responder() {
	}
	void setSuccessor(Responder *s) {
		successor = s;
	}
	//沿着链表处理   
	void handleAlert() {
		if (this->canHandle()) {
			this->handle();
		}
		else {
			if (successor != nullptr) {
				successor->handleAlert();
			}
			else {
				cout << "NO Response" << endl;
				//缺省处理
			}
		}
	}
private:
	virtual bool canHandle() = 0;
	virtual void handle() = 0;
	Responder *successor{ nullptr };
};
class EmailResponder : public Responder {
public:
	~EmailResponder() {
	}
private:
	bool canHandle() override {
		return false;
	}
	void handle() override {
		std::cout << "email the alert" << std::endl;
	}
}
;
class SMSResponder : public Responder {
public:
	~SMSResponder() {
	}
private:
	bool canHandle()  override {
		return false;
	}
	void handle() override {
		std::cout << "sms the alert" << std::endl;
	}
};
class PhoneResponder : public Responder {
public:
	~PhoneResponder() {
	}
private:
	bool canHandle()  override {
		return false;
	}
	void handle() override {
		std::cout << "call to tell the alert" << std::endl;
	}
};
class WhistleResponder : public Responder {
public:
	~WhistleResponder() {
	}
private:
	bool canHandle()  override {
		return true;
	}
	void handle() override {
		std::cout << "whistle to tell the alert" << std::endl;
	}
};
using ResponderPtr = unique_ptr<Responder>;
int main() {
	ResponderPtr responder1 = make_unique<EmailResponder>();
	ResponderPtr responder2 = make_unique<SMSResponder>();
	ResponderPtr responder3 = make_unique<PhoneResponder>();
	ResponderPtr responder4 = make_unique<WhistleResponder>();
	// 1- > 2 -> 3 ->4    
	responder1->setSuccessor(responder2.get());
	responder2->setSuccessor(responder3.get());
	responder3->setSuccessor(responder4.get());
	responder1->handleAlert();
	return 0;
}

职责链的变体:职责网,即不是链条而是有向图,更准确的说是偏序有向图。

gg浏览器的例子:

 

4,命令模式

优点:可以用来做批处理

缺点:每一个命令都要有对应的类,造成代码膨胀。

命令模式就是把不同命令封装成抽象类的不同子类,请求命令和处理命令可以分开。

处理命令的类:

class TV
{
public:
	void open()
	{
		cout << "open ";
	}
	void close()
	{
		cout << "close ";
	}
};

处理命令的抽象类和子类(每个子类封装一个处理命令的函数):

class Command
{
public:
	virtual void run() {};
};
class OpenCommond :public Command
{
public:
	OpenCommond(TV* p)
	{
		opt = p;
	}
	void run()
	{
		opt->open();
	}
private:
	TV* opt;
};
class CloseCommond :public Command
{
public:
	CloseCommond(TV* p)
	{
		opt = p;
	}
	void run()
	{
		opt->close();
	}
private:
	TV* opt;
};

调用示例:

int main()
{
	//请求命令
	auto tv = std::make_unique<TV>();
	std::vector<std::unique_ptr<Command>> script;
	script.emplace_back(std::make_unique<OpenCommond>(tv.get()));
	script.emplace_back(std::make_unique<CloseCommond>(tv.get()));
	//处理命令
	std::for_each(script.begin(), script.end(), [](auto &&command) { command->run(); });
	return 0;
}

5,迭代器模式

迭代器模式就是像STL迭代器一样,隐藏内部实现提供通用操作的类。

抽象迭代器:

class Iterator
{
public:
	virtual void getNext() {};
};

分段容器的具体迭代器:

template<typename T>
class RealIter:public Iterator
{
public:
	RealIter(vector<T> &vec) :v(vec),id(0){};
	void getNext() {
		static auto it = v[0].begin();
		Print(*it);
		it++;
		while (it == v[id].end()) {
			++id;
			if (id >= v.size())id = 0;
			it= v[id].begin();
		}
	}
private:
	vector<T>&v;
	int id;
};

其中的Print函数来自输入输出模板

抽象容器类:

class DataBase
{
public:
	virtual unsigned size() { return 0; };
	virtual void getNext() {};
	virtual void add(int a) {};
	virtual void add(int a, int b) {};
	void showAll() {
		for (int i = 0; i < size(); i++) {
			getNext();
		}
	}
};

分段Map的具体容器类:

class MyMap :public DataBase
{
public:
	MyMap() :it(vm) {
		vm.resize(10);
	}
	unsigned size() {
		return s;
	}
	void add(int a, int b)
	{
		int k = a % 10;
		if (vm[k].find(a) == vm[k].end())s++;
		vm[k][a] = b;
	}
	void getNext() {
		it.getNext();
	}
private:
	vector<map<int, int>>vm;
	unsigned s;
	RealIter<map<int, int>> it;
};

调用示例:

int main()
{
	map<int, int>mm;
	DataBase* m = new MyMap();
	m->add(1, 2);
	m->add(10, 3);
	m->add(15, 4);
	m->add(27, 5);
	m->add(44, 6);
	m->add(27, 7);
	m->add(100, 8);
	m->add(222, 9);
	m->showAll();
	return 0;
}

输出:

10 3
100 8
1 2
222 9
44 6
15 4
27 7

我是按照key的个位数来划分成10段,每段是个独立的map,所以输出也是按照个位数的顺序。

6,中介者模式

中介者模式,就是双观察者模式,以租房为例,客户可以收到所有房东信息,房东可以收到所有客户信息。

用户基类和中介类:

class Mediator;
class Person
{
public:
	void SetMeditor(Mediator* m)
	{
		med = m;
	}
	virtual void SendMessage(string s) {};
	virtual void GetMessage(string s) {};
protected:
	Mediator* med;
	string name;
};
class Mediator
{
public:
	void PushRenters(Person* p)
	{
		renters.push_back(p);
	}
	void PushLandlord(Person* p)
	{
		landlord.push_back(p);
	}
	void SendMessage(Person* p, string s)
	{
		auto it = find(renters.begin(), renters.end(), p);
		if (it != renters.end()) {
			for (auto& p : landlord)p->GetMessage(s);
		}
		else {
			for (auto& p : renters)p->GetMessage(s);
		}
	}
private:
	vector<Person*> renters;
	vector<Person*> landlord;
};

租客子类和房东子类:

class Renter :public Person
{
public:
	Renter(Mediator* m, string s)
	{
		SetMeditor(m);
		name = s;
	}
	void SendMessage(string s)
	{
		med->SendMessage(this, s);
	}
	void GetMessage(string s)
	{
		cout << name << " get message:" << s << endl;
	}
};
class Landlord :public Person
{
public:
	Landlord(Mediator* m, string s)
	{
		SetMeditor(m);
		name = s;
	}
	void SendMessage(string s)
	{
		med->SendMessage(this, s);
	}
	void GetMessage(string s)
	{
		cout << name << " get message:" << s << endl;
	}
};

调用示例:

int main()
{
	Mediator m;
	Renter r1(&m, "r1");
	Renter r2(&m, "r2");
	Landlord l1(&m, "l1");
	Landlord l2(&m, "l2");
	m.PushRenters(&r1);
	m.PushRenters(&r2);
	m.PushLandlord(&l1);
	m.PushLandlord(&l2);
	r1.SendMessage("r1 want a room");
	l1.SendMessage("l1 has a room");
	return 0;
} 

输出:

l1 get message:r1 want a room
l2 get message:r1 want a room
r1 get message:l1 has a room
r2 get message:l1 has a room

7,备忘录模式

备忘录模式就是为一个类专门创建一个保存状态数据的类。

保存状态数据的类:

class KeyValue
{
public:
	KeyValue(int val)
	{
		this->val = val;
	}
private:
	int val;
	friend class A;
};

原类本身:

class A
{
public:
	KeyValue save()
	{
		return KeyValue(val);
	}
	void load(KeyValue k)
	{
		val = k.val;
	}
	void run()
	{
		// do sth
	}
private:
	int val;
	int sthNoNeedSave;
};

还可以再搞个管理类,把KeyValue的所有对象放在一个栈里面。

因为现在序列化方法很成熟了,这个设计模式基本上没用了。

8,观察者模式

观察者模式就是在目标类中维护一个观察者列表,当更新条件触发时自动通知所有注册的观察者。

抽象观察者和具体观察者:

class Observer
{
public:
	virtual void Update()
	{
		cout << "updated!\n";
	}
};
class Observer1 :public Observer
{
public:
	virtual void Update()
	{
		cout << "Observer1 updated!\n";
	}
};
class Observer2 :public Observer
{
public:
	virtual void Update()
	{
		cout << "Observer2 updated!\n";
	}
};

抽象目标和具体目标:

class Subject
{
public:
	void Register(Observer* ob)
	{
		vobs.push_back(ob);
	}
	void Unregister(Observer* ob)
	{
		auto it = find(vobs.begin(), vobs.end(), ob);
		if (it != vobs.end())vobs.erase(it);
	}
	void Notify()
	{
		for (auto &ob : vobs)ob->Update();
	}
private:
	vector<Observer*>vobs;
};
class SubSubject: public Subject
{
public:
	void set(int x)
	{
		this->x = x;
		if (x / 100 != x0 / 100) {
			x0 = x;
			Notify();
		}
	}
	void add()
	{
		set(x + 1);
	}
private:
	int x = 0;
	int x0 = 0;
};

我设定的更新条件是被检测的x的值发生大的变化,即百位即以上的位发生变化时,通知观察者。

调用示例:

int main() 
{
	SubSubject sub;
	sub.Register(new Observer1());
	sub.Register(new Observer2());
	sub.set(98);
	sub.add();
	sub.add();
}

输出:

Observer1 updated!
Observer2 updated!

9,状态模式

状态模式就是把状态机拆开,每个状态由一个类来处理。

状态基类:

class State
{
public:
	virtual void run() {}
	virtual State* GetNext() {};
};

状态子类(单例):

template<typename T>
class SingleA {
public:
	static T& GetSingleA() {
		static T s;
		return s;
	}
protected:
	SingleA(const SingleA&) = delete;
	SingleA(SingleA&&) = delete;
	SingleA& operator=(const SingleA&) = delete;
	SingleA& operator=(SingleA&&) = delete;
	SingleA() = default;
	~SingleA() = default;
};

class StateA :public State,public SingleA<StateA>
{
	friend class SingleA<StateA>;
public:
	void run()
	{
		// do sth
	}
	State* GetNext();
};
class StateB :public State, public SingleA<StateB>
{
	friend class SingleA<StateB>;
public:
	void run()
	{
		// do sth
	}
	State* GetNext();
};
State* StateA::GetNext()
{
	return &StateB::GetSingleA();
}
State* StateB::GetNext()
{
	return &StateA::GetSingleA();
}

处理类:

class Process
{
public:
	Process(State* state)
	{
		this->state = state;
	}
	void run()
	{
		state->run();
		state = state->GetNext();
	}
private:
	State* state;
};

10,策略模式

策略模式和模板方法模式非常像,我个人理解场景是一样的,实现方式略有区别。

策略模式是把有差异的操作抽象成虚基类(策略工厂),不同的场景各自继承虚基类实现差异化操作,主流程类把虚基类的指针作为数据成员,用它来调用实际的操作(多态)。

代码:

#include<iostream>
using namespace std;

class dress
{
public:
	virtual void dressCoat() = 0;
	virtual void dressPants() = 0;
	virtual void dressShoes() = 0;
};

class dressRed :public dress
{
public:
	void dressCoat() {
		cout << "Red coat ";
	}
	void dressPants() {
		cout << "Red pants ";
	}
	void dressShoes() {
		cout << "Red shoes ";
	}
};

class dressBlue :public dress
{
public:
	void dressCoat() {
		cout << "Blue coat ";
	}
	void dressPants() {
		cout << "Blue pants ";
	}
	void dressShoes() {
		cout << "Blue shoes ";
	}
};

class run
{
public:
	run(dress* p)
	{
		this->p = p;
	}
	void dressAll()
	{
		p->dressCoat();
		p->dressPants();
		p->dressShoes();
		cout << endl;
	}
private:
	dress* p;
};

int main()
{
	run* runRed = new run(new dressRed);
	runRed->dressAll();
	run* runBlue = new run(new dressBlue);
	runBlue->dressAll();
	return 0;
}

这个代码其实已经和CRTP+模板方法模式的实现代码非常接近了。

11,访问者模式

访问者模式的场景是,不同的操作和不同的对象之间正交,即任一操作都可用于任一对象。

实现方法是提供操作基类和对象基类,不同操作和不同对象分别继承父类(双重多态分发)。

抽象操作和具体操作:

class Pick
{
public:
	virtual void run() {};
};
class PickBig
{
public:
	void run()
	{
		cout << "pick big ";
	}
};
class PickSmall
{
public:
	void run()
	{
		cout << "pick small ";
	}
};

抽象对象和具体对象:

class Animal
{
public:
	void SetOpt(Pick* p)
	{
		opt = p;
	}
	virtual void run() {};
protected:
	Pick* opt;
};
class Pig :public Animal
{
public:
	void run()
	{
		opt->run();
		cout << "Pig\n";
	}
};
class Dog :public Animal
{
public:
	void run()
	{
		opt->run();
		cout << "Dog\n";
	}
};

调用示例:

int main()
{
	Pick* p1 = new PickBig();
	Pick* p2 = new PickSmall();
	Animal* animal = new Pig();
	animal->SetOpt(p1);
	animal->run();
	animal->SetOpt(p2);
	animal->run();
	animal = new Dog();
	animal->SetOpt(p1);
	animal->run();
	animal->SetOpt(p2);
	animal->run();
	return 0;
} 

输出:

pick big Pig
pick small Pig
pick big Dog
pick small Dog

  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值