设计模式实践

Talk is cheap,show me the code.
拥抱变化

前言

网上的设计模式分析多得是,本文章主要是提供简单有效、突出重点的设计模式实践例子

UPD

对大鸟的很多讲解没有理解好,后面还会持续更新

心得体会

设计模式就是对一些常见问题的解决方案
很多设计模式的运用就是对原则的运用,通过这些例子加深对原则的理解,是重点
封装就是屏蔽细节
继承是开放扩展
把虚函数调用看成消息,多态就等效于自动派发消息
通过static_cast + 硬编码类信息,也可以实现多态

目录

0.设计模式原则
1.简单工厂模式
2.策略模式
6.装饰模式
7.代理模式
8.工厂模式
9.原型模式
10.模板方法模式
12.外观模式
13.建造者模式
14.观察者模式
15.抽象工厂模式
16.状态模式
17.适配器模式
18.备忘录模式
19.组合模式
20.迭代器模式
21.单例模式
22.桥接模式
23.命令模式
24.职责链模式
25.中介者模式
26.享元模式,咕咕咕
27.解释器模式,咕咕咕
28.访问者模式,咕咕咕

0.设计模式原则

1.单一职责

就一个类而言,应该仅有一个引起它变化的原因

2.开放-封闭

软件实体,应该可以扩展,但是不可以修改
PS:很多时候修改是无法避免的,良好的设计应该最小化修改的影响
在有些情况下,不扩展更好,视情况而定

3.依赖倒转

1.高层模块不应该依赖底层模块。二者都应该依赖抽象
2.抽象不应该依赖细节,细节应该依赖抽象

4.里氏代换

子类型必须能够替换父类型

5.最少知识

如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用
如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三方转发这个操作

1.简单工厂模式

需求

实现一个简单计算器,要求输入两个数和运算符号,得到结果

变化点

需要增加二元运算符号类型

设计分析

二元运算的流程是固定的,采用简单工厂来动态配置子类

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
class operation
  {
  	public :
	  virtual ll get_result(ll a,ll b) = 0;
  };
class operation_add : public operation
  {
  	public :
	  ll get_result(ll a,ll b)
	    {
	    	return a + b;
		 } 
  };
class operation_sub : public operation
  {
  	public :
	  ll get_result(ll a,ll b)
	    {
	    	return a - b;
		 } 
  };
class operation_mul : public operation
  {
  	public :
	  ll get_result(ll a,ll b)
	    {
	    	return a * b;
		 } 
  };
class operation_div : public operation
  {
  	public :
	  ll get_result(ll a,ll b)
	    {
	    	if (b == 0)
	    	  exit(-1);
	    	else
	    	  return a / b;
		 } 
  };
operation* create_operation(string op_name)
  {
  	if (op_name == "+")
  	  return new operation_add();
  	else if (op_name == "-")
  	  return new operation_sub;
  	else if (op_name == "*")
  	  return new operation_mul;
  	else if (op_name == "/")
  	  return new operation_div;
  	exit(-1);
  }
ll get_result(ll number_a,string op_name,ll number_b)
  {
  	auto op = create_operation(op_name);
  	ll ret = op -> get_result(number_a,number_b);
  	delete op;
  	return ret;
  }
int main()
  {
  	ll number_a,number_b;
  	string op_name;
  	cin >> number_a >> op_name >> number_b;
  	cout << get_result(number_a,op_name,number_b);  
	return 0;
  }

2.策略模式

需求

开发一个收银系统,每次输入一个商品的单价 + 数量,计算收费

变化点

1.正常计算
2.增加满100减20,慢300减50,满700减100
3.实现满100打八折,直接打八折等

设计分析

采用cash_context类来动态配置三种计费策略

和简单工厂的区别

策略模式和简单工厂模式很相似
有一个很明显的区别就是

cash_super cs = create_cash_streaty();
... = cs.get_result();

cash_context cs = cash_context();
... = cs.get_result();

因为工厂方法需要知道工厂 + 基类命,而策略模式需要知道cash_context的名字
这就是他们的区别,工厂模式更为普适性一点,而策略模式只生成一个算法族

struct cash_super;
struct cash_rebate : cash_super;
struct cash_return : cash_super;
```的层次结构

``` c++
#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct cash_super
  {
  	virtual ll get_result(ll price,ll number)
  	  {
  	  	return price * number;
		}
  };
struct cash_rebate : cash_super
  {
  	ll con,zhe;
  	cash_rebate(ll con,ll zhe)
  	  :con(con),zhe(zhe)
		{}
  	virtual ll get_result(ll price,ll number)
  	  {
  	  	ll cost = price * number;;
  	  	if (cost >= con)
  	  	  cost = cost * zhe / 10;
  	  	return cost;
		}
  };
struct cash_return : cash_super
  {
  	ll con,ret;
  	cash_return(ll con,ll ret)
  	  :con(con),ret(ret)
		{}
  	virtual ll get_result(ll price,ll number)
  	  {
  	  	ll cost = price * number;;
  	  	if (cost >= con)
  	  	  cost -= ret;
  	  	return cost;
		}
  };
struct cash_context
  {
  	cash_super *cs;
  	cash_context(string strategy)
  	  {
  		if (strategy == "正常收费")
		  cs = new cash_super();
		else if (strategy == "满100减10")
		  cs = new cash_return(100,10);
		else if (strategy == "满100打8折")
		  cs = new cash_rebate(100,8);
		}
	ll get_result(ll price,ll number)
	  {
	  	return cs -> get_result(price,number);
	  }
	~cash_context()
	  {
	    delete cs; 	
	  }
  };
int main()
  {
  	ll price,number;
  	cin >> price >> number;
  	cout << cash_context("正常收费").get_result(price,number) << endl;
  	cout << cash_context("满100减10").get_result(price,number) << endl; 
  	cout << cash_context("满100打8折").get_result(price,number) << endl; 
	return 0;
  }

6.装饰模式

需求

设计一个,简单的服饰系统

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
void wear_suit()
  {
  	cout << "suit" << endl;
  }
void wear_tie()
  {
  	cout << "tie" << endl;
  }
void wear_shose()
  {
  	cout << "shose" << endl;
  }
void show_home()
  {
    cout << "in home" << endl;
   	wear_suit();
  	wear_shose();
  }
void show_work()
  {
  	cout << "in work" << endl;
  	wear_suit();
  	wear_tie();
  	wear_shose();
  }
int main()
  {
  	show_home();
  	show_work();
	return 0;
  }

变化

变化穿衣方式

设计分析

装饰模式,非常神奇的一个模式
大概就是通过指针把一串功能串起来
就像是windows中的管道,可以动态配置管道
相对于常规的动态组合调用链的方式,装饰模式通过三层类层次设计,可以很好的封装变化

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct person
  {
  	string name;
  	virtual void show()
  	  {
  	  	cout << "装扮的 " << name << "\n";
		}
  };
struct decotator : person
  {
  	person *next;
  	void decorate(person* component)
  	  {
  	  	next = component;
		}
	virtual void show()
	  {
	  	if (next)
	  	  {
	  	  	next -> show();
			}
	  }
  };
struct suit : decotator
  {
  	virtual void show()
  	  {
  	  	cout << "suit" << "\n";
  	  	this -> decotator::show();
		}
   }; 
struct mytie : decotator
  {
  	virtual void show()
  	  {
  	  	cout << "tie" << "\n";
  	  	this -> decotator::show();
		}
   }; 
struct shirt : decotator
  {
  	virtual void show()
  	  {
  	  	cout << "shirt" << "\n";
  	  	this -> decotator::show();
		}
   }; 
int main()
  {
  	suit a;
  	mytie b;
  	shirt c;
  	person p;
  	p.name = "小菜"; 
  	a.decorate(&p);
  	b.decorate(&a);
  	c.decorate(&b);
  	c.show();
  	cout << endl;
  	a.decorate(&p);
  	c.decorate(&a);
  	c.show();
  	return 0;
  }

7.代理模式

需求

设计一个代理

与外观模式的区别

外观模式是一种组合模式,而代理模式是一种继承模式
外观模式的目的是重组子系统
而代理模式是,给真实的对象加壳,方便在壳上添加功能而不引起客户端和真实对象的变化
这个模式是迪米佳法则的运用

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct gift
  {
  	virtual void give_bool() = 0;
    virtual void give_food() = 0;
  };
struct pursuit : gift
  {
    string name;
  	pursuit(string name)
  	  :name(name)
  	    {}
  	void give_bool()
  	  {
  	  	cout << name << " give_bool" << endl;
		 }
	void give_food()
	  {
	  	cout << name << " give_food" << endl;
	   } 
  };
struct proxy : gift
  {
  	pursuit* real;
  	proxy(string name)
  	  :real(new pursuit(name))
  	    {}
  	void give_bool()
  	  {
  	  	real -> give_bool();
		 }
	void give_food()
	  {
	  	real -> give_food();
	   } 
  };
int main()
  {
  	auto p = new proxy("mzb");
  	p -> give_bool();
	return 0;
  }

8.工厂模式

需求

设计一个工厂,可以按需求生产学雷锋的学生和志愿者

设计分析

设计一个工厂有接口create()
然后对于扩展,直接通过继承扩展工厂

和简单工厂的区别

封闭了修改,开放了扩展
相当于把简单工厂再次抽象 : 用工厂.create() + 虚函数代替了简单工厂中的switch
emm...就是简单工厂的一个抽象,产品种类固定就简单工厂,有扩展就工厂模式

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct lei_feng
  {
  	virtual void sweep()
  	  {
  	  	cout << "扫地" << endl;
		}
  	virtual void wash()
  	  {
  	  	cout << "洗衣服" << endl;
		}
	virtual void buy_rice()
	  {
	  	cout << "卖大米" << endl;
	  }
  };
struct student : lei_feng
  {
  	virtual void sweep()
  	  {
  	  	cout << "student 扫地" << endl;
		}
  	virtual void wash()
  	  {
  	  	cout << "student 洗衣服" << endl;
		}
	virtual void buy_rice()
	  {
	  	cout << "student 卖大米" << endl;
	  }
  };
struct volunteer : lei_feng
  {
  	virtual void sweep()
  	  {
  	  	cout << "volunteer 扫地" << endl;
		}
  	virtual void wash()
  	  {
  	  	cout << "volunteer 洗衣服" << endl;
		}
	virtual void buy_rice()
	  {
	  	cout << "volunteer 卖大米" << endl;
	  }
  };
struct factory
  {
  	virtual lei_feng* create() = 0;
  };
struct student_factory : factory
  {
  	virtual lei_feng* create()
  	  {
  	  	return new student();
		}
  };
struct volunteer_factory : factory
  {
  	virtual lei_feng* create()
  	  {
  	  	return new volunteer();
		}
  };
int main()
  {
  	auto fac = new volunteer_factory();
  	auto peo = fac -> create();
  	peo -> wash();
	return 0;
  }

9.原型模式

需求

通过基类指针,复制出一个继承类对象

设计分析

可以通过CTRP的方式,硬编码类信息 + static_cast低消耗滋滋这个操作,这里我还是写了一个虚函数实现

关于深浅复制

深复制:拷贝资源
浅复制:不拷贝资源
jvav里面比较麻烦...c++里面就很简单了

typeid

typeid(指针),得到的是指针的编译期类型信息
typeid(*指针),得到的是运行时对象的信息
dynamic_cast依赖于typeid

c++中的协变

c++中的虚函数要求参数、返回值类型一致
有一个重要的例外:虚函数返回该对象的引用,指针的时候,允许返回值类型不一致
...感觉有点多余,我调用该对象的时候,发生的安全的static_cast...只不过从语法上简化了一下
参数不能协变,参数协变的时候,虚函数等效于普通函数

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct base
  {
  	virtual base* clone()
  	  {
  	  	return new base(*this);
		}
  };
struct son : base
  {
  	ll val;
  	son(ll val)
  	  :val(val)
  	    {}
  	virtual son* clone()
  	  {
  	  	return new son(*this);
		}
  };
int main()
  {
  	base *a = new base();
  	base *b = new son(10);
  	base *c = b -> clone(); 
  	cout << typeid(*a).name() << endl;
  	cout << typeid(*b).name() << endl; 
  	cout << typeid(*c).name() << endl;
	return 0;
  }

10.模板方法模式

需求

设计一套试卷,要求两个学生填写试卷

设计分析

把“试卷”这个公共方法,提取到基类,然后把“答案”方法延迟到子类
这里采用CRTP实现...非常合适...不必死套继承
CRTP突出了这个模式的精髓

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
template<typename T>
struct test_paper
  {
  	T& cast()
  	  {
  	  	return static_cast<T&>(*this); // safe
		}
	void question1()
	  {
	  	cout << "1.你的名字是 ";
		cast().answer1(); 
		cout << endl;
	   } 
	void question2()
	  {
	  	cout << "2.你的偶像是 ";
		cast().answer2(); 
		cout << endl;
	   }  
  }; 
struct student1 : test_paper<student1>
  {
  	void answer1()
  	  {
  	  	cout << "mzb";
		}
	void answer2()
	  {
	  	cout << "无"; 
	  }
  };
struct student2 : test_paper<student2>
  {
  	void answer1()
  	  {
  	  	cout << "wmk";
		}
	void answer2()
	  {
	  	cout << "mzb"; 
	  }
  };
int main()
  {
  	student1 a;
  	student2 b;
  	a.question1();
  	b.question1();
  	a.question2();
  	b.question2();
	return 0;
  }

12.外观模式

需求

变化点

设计分析

补充

说白了,外观模式就是把一系列流程分装到一起
客户端和子系统都只需要和外观交互,降低了耦合
值得一提的是接待员并不看病,也就是外观不添加新的功能,也就是外观一般不需要继承

13.建造者模式

需求

生产两种产品,生产产品的过程稳定

设计分析

把生产过程抽象出来 + 一个指挥函数建造产品

指挥函数仍旧是迪米佳法则的运用

...迪米佳法则真的常见

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct product
  {
  	vector<string> part;
  	void add(string rhs)
  	  {
  	  	part.push_back(rhs);
		}
	void show()
	  {
	  	cout << "产品 : ";
	  	for (auto it : part)
	  	  cout << it << " ";
	  	cout << "\n";
	  }
  };
struct builder
  {
  	virtual void get_part1() = 0;
  	virtual void get_part2() = 0;
    virtual product get_result() = 0;
  };
struct concrete_builder1 : builder
  {
  	product pro;
  	void get_part1()
  	  {
  	  	pro.add("部件 1"); 
		}
	void get_part2()
	  {
	  	pro.add("部件 2"); 
	  }
	product get_result()
	  {
	  	return pro;
	  }
  };
struct concrete_builder2 : builder
  {
  	product pro;
  	void get_part1()
  	  {
  	  	pro.add("部件 X"); 
		}
	void get_part2()
	  {
	  	pro.add("部件 Y"); 
	  }
	product get_result()
	  {
	  	return pro;
	  }
   }; 
product director(builder *rhs)
  {
  	rhs -> get_part1();
  	rhs -> get_part2();
  	return rhs -> get_result();
  }
int main()
  {
  	auto ret1 = director(new concrete_builder1);
  	ret1.show();
  	auto ret2 = director(new concrete_builder2);
  	ret2.show();
	return 0;
  }

14.观察者模式

需求

将若干观察者关联到同一个事件源,当有事件来临,所有观察者都被通知

设计分析

设计事件、观察者两个类层次结构
...代码写的很清楚

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;

struct observer
  {
  	string name;
  	observer(string name)
  	  : name(name)
  	    {}
  	virtual void update() = 0;
  };
struct stock_observer : observer
  {
  	stock_observer(string name)
  	  :observer(name)
  	    {}
  	virtual void update()
  	  {
  	  	cout << name << " 关闭炒股平台" << endl;
		}
  };
struct TV_observer : observer
  {
  	TV_observer(string name)
  	  : observer(name)
  	    {}
  	virtual void update()
  	  {
  	  	cout << name << " 关闭电视" << endl;
		}
  };
struct subject
  {
  	virtual void attach(observer *obs) = 0;
  	virtual void detach(observer *obs) = 0;
  	void notify();
  };
struct boss : subject
  {
  	set<observer*> observers;
  	virtual void attach(observer *obs)
  	  {
  	  	observers.insert(obs);
		}
	virtual void detach(observer *obs)
	  {
	  	observers.erase(obs);
	  }
	void notify()
	  {
	  	for (auto it : observers)
	  	  it -> update();
	  }
  };
int main()
  {
  	observer *a = new stock_observer("mzb");
	observer *b = new TV_observer("wmk");
	::boss boss;
	boss.attach(a);
	boss.attach(b);
	boss.notify(); 
	return 0;
  }

15.抽象工厂模式

需求

需要和mysql交互

变换

改成和SQL交互

设计分析

采用简单工厂 + 工厂模式

其他

在大鸟的书里,抽象工厂 = 简单工厂改进的多接口工厂
因为多接口的工厂,修改的时候非常麻烦,简单工厂改进之后就简单很多

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct user
  {
  	virtual void get() = 0;
  	virtual void set() = 0;
  };
struct sql_user : user
  {
  	virtual void get()
  	  {
  	  	cout << "user get data from sql" << endl;
		}
	virtual void set()
	  {
	  	cout << "user set data from sql" << endl;
	  }
  };
struct mysql_user : user
  {
  	virtual void get()
  	  {
  	  	cout << "user get data from mysql" << endl;
		}
	virtual void set()
	  {
	  	cout << "user set data from mysql" << endl;
	  }
  };
struct department
  {
  	virtual void get() = 0;
  	virtual void set() = 0;
  };
struct sql_department : department
  {
  	virtual void get()
  	  {
  	  	cout << "department get data from sql" << endl;
		}
	virtual void set()
	  {
	  	cout << "department set data from sql" << endl;
	  }
  };
struct mysql_department : department
  {
  	virtual void get()
  	  {
  	  	cout << "department get data from mysql" << endl;
		}
	virtual void set()
	  {
	  	cout << "department set data from mysql" << endl;
	  }
  };
struct data_access
  {
  	static string get_db()
  	  {
  	  	return "sql";
		}
  	static user* create_user()
  	  {
  	  	if (get_db() == "mysql")
  	  	  return new mysql_user();
  	  	else
  	  	  return new sql_user();
		}
	static department* create_department()
  	  {
  	  	if (get_db() == "mysql")
  	  	  return new mysql_department();
  	  	else
  	  	  return new sql_department();
		}
  };
int main()
  {
  	auto p1 = data_access::create_user();
  	p1 -> get();
  	auto p2 = data_access::create_department();
	p2 -> set(); 
	return 0;
  }

16.状态模式

需求

需要根据时间的变化,动态改变类的功能

变化

动态修改

理解

就是避免写一堆if-else,并且利用类方便的修改
emmm,时间是个线性关系,可以用组合 + 数据结构的方式来实现,似乎组合的方式在这里更合适

吐槽

jvav可以调用不完全类型?
大鸟的书里有两三次,这个情况
...可以调用不完全类型的成员...可能因为jvav动态加载类,静态加载要确定类的内存布局才能调用

17.适配器模式

这个模式非常常见,也非常简单,比如STL中的stack的queue都是封装deque,也就是所谓的容器适配器
注意,适配器中一般是has-a关系,而不是is-a关系

18.备忘录模式

多和不多出来一个管理类的区别
这个是迪米佳法则的直接体现
我第一次看很懵逼这个manager的作用,感觉非常多余,其实不是这样的
考虑 : 备忘录很大,我需要把它存在磁盘上
如果你采用了没有管理类的实现,你会发现player和备忘录耦合的非常紧密
加一个管理类就很轻松了,player和备忘录都只和管理类交互,管理类可以自由处理备忘录的存储方式
耦合就解开了,非常妙
简单的设计模式也可能有深刻的道理,不到轻视

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct memento
  {
  	ll life;
  	memento(ll life)
  	  :life(life)
  	    {}
  };
struct player
  {
  	ll life;
  	player()
  	  :life(100)
  	    {}
  	memento get()
  	  {
  	  	return memento(life);
		}
	void set(memento rhs)
	  {
	  	life = rhs.life;
	  }
  };
struct manager
  {
  	memento mem;
  	manager()
  	  :mem(0)
		{}
  };
int main()
  {
  	player p;
  	manager admin;
  	admin.mem = p.get();
  	p.set(admin.mem);
	return 0;
  }

19.组合模式

需求

需要如操作单个对象一般操作多个对象,一般是操作整个树形结构

设计分析

这里有一个比较关键的问题叶子和非叶子节点的关系

1.透明模式

叶子中也具有增删函数,但是没有实现的意义...也没有作为接口的意义

2.安全模式

叶子中没有增删函数,需要客户端判断
这里采用安全模式,透明模式比较简单
因为需要异类容器,所以只能通过丑陋的static_cast转型之后在叶子的父亲上调用add
这就要求程序员精确的规划static_cast使用不当会使得程序崩溃

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct component
  {
  	string name;
  	component(string name)
  	  :name(name)
  	    {}
  	virtual void show(ll) = 0;
  };
struct leaf : component
  {
  	leaf(string name)
  	  :component(name)
  	    {}
  	void show(ll depth = 0)
	  {
	  	cout << string(depth * 2,'-') << name << "\n";
	   } 
  };
struct composite : component
  {
  	composite(string name)
  	  :component(name)
  	    {}
  	vector<component*> son;
  	void add(component* rhs)
  	  {
  	  	son.emplace_back(rhs);
		}
	void show(ll depth = 0)
	  {
	  	cout << string(depth * 2,'-') << name << "\n";
	  	for (auto it : son)
	  	  it -> show(depth + 1);
	  }
  };
int main()
  {
  	auto root = new composite("总部");
	root -> add(new leaf("办事处1"));
	root -> add(new composite("街道"));
	root -> add(new leaf("办事处2"));
	auto &son = root -> son[1];
	static_cast<composite*>(son) -> add(new leaf("街道办事处")); 
	root -> show();
	return 0;
  }

20.迭代器模式

这个看c++::STL的设计
采用模板 + auto + 模板元 + 迭代器tag继承的方式,已经非常完美了
特别是STL设计的五种迭代器构型,非常的好,直接用就行了
特别是继承 + 编译器函数分发的机制,非常的高效 + 优雅,屏蔽了细节并简化了设计

21.单例模式

需求

要求某个类只能产生一个实例

设计分析

CTRP实现,注意把默认生成的拷贝构造delete掉

其他

多线程产生的问题后面再弄
懒汉式,饿汉式区别不大,饿汉式无非弄成静态成员

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
template<typename T>
struct signle
  {
  	static T& get_signle()
  	  {
  	  	static T ret;
  	  	return ret;
		}
  };
struct base : signle<base>
  {
  	friend class signle<base>;
  	protected :
  		base()
  		  {
  		  	cout << "debug+base()" << endl; 
			}
		base(base const&) = delete;
   }; 
int main()
  {
  	auto &ret = base::get_signle();
	return 0;
  }

22.桥接模式

需求

开发若干个品牌的若干个产品

设计分析

用组合取代继承爆炸的问题

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct software
  {
  	virtual void run() = 0;
  };
struct huawei_game : software
  {
  	virtual void run()
  	  {
  	  	cout << "运行 华为 手机游戏" << endl;
		}
  };
struct xiaomi_game : software
  {
  	virtual void run()
  	  {
  	  	cout << "运行 小米 手机游戏" << endl;
		}
   };
struct phone
  {
  	software *soft;
  	virtual void run() = 0;
  	void set(software *rhs)
  	  {
  	  	soft = rhs;
		}
  };
struct xiaomi : phone
  {
  	virtual void run()
  	  {
  	  	soft -> run();
		}
  };
struct huawei : phone
  {
  	virtual void run()
  	  {
  	  	soft -> run();
		}
  };
int main()
  {
  	auto a = new huawei();
  	auto b = new xiaomi();
  	a -> set(new huawei_game());
  	b -> set(new xiaomi_game());
	a -> run();
	b -> run();
	return 0;
  }

23.命令模式

需求

模拟烧烤店

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct barbecuer
  {
  	void make_chiken()
  	  {
  	  	cout << "师傅 烤鸡翅" << endl;
		}
	void make_mutton()
	  {
	  	cout << "师傅 烤羊肉串" << endl;
	  }
  };
struct command
  {
  	barbecuer peo;
  	command(barbecuer peo)
  	  :peo(peo)
  	    {}
  	virtual void excute() = 0;
  	virtual string to_string() = 0;
  };
struct make_mutton : command
  {
  	make_mutton(barbecuer peo)
  	  :command(peo)
  	    {}
  	virtual void excute()
  	  {
  	  	peo.make_mutton();
		}
	virtual string to_string()
	  {
	  	return "mutton";
	  }
  };
struct make_chiken : command
  {
  	make_chiken(barbecuer peo)
  	  :command(peo)
  	    {}
  	virtual void excute()
  	  {
  	  	peo.make_chiken();
		}
	virtual string to_string()
	  {
	  	return "chiken";
	  }
  };
struct waiter
  {
  	vector<pair<string,command*>> v;
  	void set_order(command *rhs)
  	  {
  	  	v.emplace_back("log : " + rhs -> to_string(),rhs);	  
		}
	void notify()
	  {
	  	for (auto it : v)
	  	  it.second -> excute();
	  }
	void show()
	  {
	  	cout << endl << "订单记录" << endl;
	  	for (auto it : v)
	  	  cout << it.first << "\n";
	  }
  };
int main()
  {
  	barbecuer peo;
  	command *mut = new make_mutton(peo);
  	command *chi = new make_chiken(peo);
  	waiter wai;
  	wai.set_order(mut);
  	wai.set_order(chi);
  	wai.notify(); 
  	wai.show();
  	return 0;
  }

24.职责链模式

需求

沿着某条链,层层处理一个请求
和装饰模式很相似...也比较简单...感觉就是很简单的抽象一下职责链

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct manager
  {
  	string name;
  	manager* father;
  	manager(string name)
  	  :name(name)
  	    {}
  	void set(manager* fa)
  	  {
  	  	father = fa;
		}
	virtual void check(string,ll) = 0;
  };
struct common_manager : manager
  {
  	common_manager(string name)
  	  :manager(name)
  	    {}
  	virtual void check(string type,ll num)
  	  {
  	  	if (type == "请假" and num <= 2)
  	  	  {
  	  	  	cout << name << " 批准 " << type << " " << num << endl; 
			  }
		else if (father != nullptr)
		  {
		  	father -> check(type,num);
		  }
		}
  };
struct major_manager : manager
  {
  	major_manager(string name)
  	  :manager(name)
  	    {}
  	virtual void check(string type,ll num)
  	  {
  	  	if (type == "加薪" and num <= 2000)
  	  	  {
  	  	  	cout << name << " 批准 " << type << " " << num << endl; 
			  }
		else if (father != nullptr)
		  {
		  	father -> check(type,num);
		  }
		}
  };
struct general_manager : manager
  {
  	general_manager(string name)
  	  :manager(name)
  	    {}
  	virtual void check(string type,ll num)
  	  {
  	  	cout << name << " 批准 " << type << " " << num << endl; 
		}
  };
int main()
  {
  	auto a = new common_manager("总监");
  	auto b = new major_manager("总经理");
  	auto c = new general_manager("董事");
  	a -> set(b);
  	b -> set(c);
  	a -> check("请假",2);
  	a -> check("加薪",200);
  	a -> check("加薪",2000 + 110);
	return 0;
  }

25.中介者模式

需求

模拟联合国

设计分析

很自然的做抽象就行了
如果只有一个中介者,抽象中介者就没必要了

缺点

中介者的职责比较大,意味着中介者一旦出问题,需要修改的地方会非常多
主要用来处理多个对象的复杂通信问题

注意点

没有get到这个模式的精髓qwq
不过只能存不完全类型的指针或者引用,不能访问不完全类型的成员函数和成员对象

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct mediator;
struct country
  {
  	string name;
  	mediator *media;
  	country(string name,mediator *media)
  	  :name(name),media(media)
  	    {}
  	virtual void  get(string,string) = 0;
  	virtual void send(string,string) = 0;
  };
struct mediator
  {
  	map<string,country*> member;
  	void attach(country* rhs)
  	  {
  	  	member[rhs -> name] = rhs;
		}
	void send(string from,string to,string message)
	  {
	  	member[to] -> get(from,message);
	  }
  };
struct china : country
  {
  	china(mediator *media)
  	  :country("china",media)
  	    {
  	    	media -> attach(this);
		  }
  	void get(string from,string message)
  	  {
  	  	cout << "收到来自 " << from << " 的消息 : " << message << endl; 
		}
	void send(string to,string message)
	  {
	  	media -> send(name,to,message);
	  }
  };
struct india : country
  {
  	india(mediator *media)
  	  :country("india",media)
  	    {
  	    	media -> attach(this);
		  }
  	void get(string from,string message)
  	  {
  	  	cout << "收到来自 " << from << " 的消息 : " << message << endl; 
		}
	void send(string to,string message)
	  {
	  	media -> send(name,to,message);
	  }
  };
int main()
  {
  	auto media = new mediator;
  	auto a = new china(media);
  	auto b = new india(media);
  	a -> send("india","hello");
  	b -> send("china","你好");
	return 0;
  }



posted @ 2021-05-24 16:22  XDU18清欢  阅读(90)  评论(0)    收藏  举报