订阅号怎么做网站,广告公司简介简短大气,wordpress主题发布,黄冈最专业的公司网站建设平台设计模式
设计模式是什么
设计模式是指在软件开发中#xff0c;经过验证的#xff0c;用于解决在特定环境下#xff0c;重复出现的#xff0c;特定问题的解决方案#xff1b;其实就是解决问题的固定套路。但是要慎用设计模式#xff0c;有一定的工程代码量之后用它比较…设计模式
设计模式是什么
设计模式是指在软件开发中经过验证的用于解决在特定环境下重复出现的特定问题的解决方案其实就是解决问题的固定套路。但是要慎用设计模式有一定的工程代码量之后用它比较好。
设计模式怎么来的
满足设计原则后然后慢慢迭代出来的
设计模式解决了什么问题?
前提具体需求既有稳定点又有变化点。全是稳定点或者全是变化点游戏开发脚本语言都不要用。我们期望修改少量的代码就可以适应需求的变化。 一个比喻整洁的房间好动猫怎么保证房间的整洁? 就是把猫关在一个笼子里这个猫就是我们需求把猫关在笼子中就是设计模式。
设计模式的基础
面向对象的思想
封装主要是隐藏实现细节实现模块化 继承无需修改原有类的情况下通过继承实现对功能的扩展 多态静态多态函数重载。 多态动态多态继承中虚函数重写。 这个就是多态
设计原则
依赖倒置
高层模块不应该依赖低层模块两者都应该依赖抽象抽象不应该依赖具体实现具体实现应该依赖于抽象 自动驾驶系统公司是高层汽车生产厂商为低层它们不应该互相依赖一方变动另一方也会跟着变动而应该抽象一个自动驾驶行业标准高层和低层都依赖它这样以来就解耦了两方的变动自动驾驶系统、汽车生产厂商都是具体实现它们应该都依赖自动驾驶行业标准抽象接口的使用者不要依赖具体的实现。要依赖具体的接口。
开放封闭 主要针对封装和多态 一个类应该对扩展组合和继承开放对修改关闭
面向接口 主要针对封装
不将变量类型声明为某个特定的具体类而是声明为某个接口客户程序无需获知对象的具体类型只需要知道对象所具有的接口减少系统中各部分的依赖关系从而实现“高内聚、松耦合”的类型设计方案
封装变化点 主要针对封装和多态 将稳定点和变化点分离扩展修改变化点让稳定点和变化点的实现层次分离
单一职责 一个类应该仅有一个引起它变化的原因
里氏替换 主要针对多态 子类型必须能够替换掉它的父类型主要出现在子类覆盖父类实现原来使用父类型的程序可能出现错误覆盖了父类方法却没有实现父类方法的职责
接口隔离
不应该强迫客户依赖于它们不用的方法一般用于处理一个类拥有比较多的接口而这些接口涉及到很多职责客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。
组合优于继承 继承耦合度高组合耦合度低
最小知道原则 对这个类知道的越少越好只要知道接口就行
如何学习设计模式
明确目的
新手在现有设计模式的基础上扩展代码 老手做功能抽象时如何选择设计模式
学习步骤
该设计模式解决了什么问题
稳定点变化点
该设计模式的代码结构是什么
符合哪些设计原则
如何在上面扩展代码
该设计模式有哪些典型应用场景
联系工作场景开源框架
设计模式-模块方法
第一个设计模式模块方法
定义
定义一个操作中的算法的骨架 而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 ——《 设计模式》 GoF 背景 某个品牌动物园有一套固定的表演流程但是其中有若干个表演子流程可创新替换以尝试迭代更新表演流程这个和上面定义差不多。
解决问题
解决问题稳定点就是算法骨架变化点就是重定义该算法的某些特定步骤子流程需要变化。
代码结构
基类中有骨架流程接口上面代码中就是那个show()函数中有show1(),show2()所有子流程对子类开放并且是虚函数protected多态使用方式,用基类指针new一个扩展类
有虚函数并且被protected方法修饰90%是我们的模板方法。
我们来实现这个某个品牌动物园有一套固定的表演流程但是其中有若干个表演子流程可创新替换以尝试迭代更新表演流程这个和上面定义差不多。
来看一个代码对比第一个代码是没有设计模式的第二个代码是用了设计模式的
#include iostream
using namespace std;// 设计原则
// 1. 设计原则演变过来的 2.符合设计原则的代码只需要修改少量代码就可以演变成设计模式
// 接口隔离原则 1. 类封装 权限限定词(private,public....)来实现 2. 类与类依赖 接口依赖注入
// 最小知道原则
// 破坏了哪些设计原则
// 单一职责变化方向 封装
// 开闭原则 对扩展开放 对修改关闭
// 扩展方式继承多态组合
class ZooShow {
public:ZooShow(int type 1) : _type(type) {}public:void Show() {if (Show0())PlayGame();Show1();Show2();Show3();}private://不能让其选择show0()show1(),show2().void PlayGame() {cout after Show0, then play game endl;}bool Show0() {if (_type 1) {// return true;} else if (_type 2 ) {// ...} else if (_type 3) {}cout _type show0 endl;return true;}void Show1() {if (_type 1) {cout _type Show1 endl;} else if (_type 2) {cout _type Show1 endl;} else if (_type 3) {}}void Show2() {if (_type 20) {}cout base Show2 endl;}void Show3() {if (_type 1) {cout _type Show1 endl;} else if (_type 2) {cout _type Show1 endl;}}
private:int _type;
};int main () {ZooShow *zs new ZooShow(1);zs-Show();return 0;
}
用了设计模式
#include iostream
using namespace std;// 开闭
class ZooShow {
public:void Show() {// 如果子表演流程没有超时的话进行一个中场游戏环节如果超时直接进入下一个子表演流程if (Show0())PlayGame();Show1();Show2();Show3();}private:void PlayGame() {cout after Show0, then play game endl;}bool expired;// 对其他用户关闭但是子类开放的
protected:virtual bool Show0() {cout show0 endl;if (! expired) {return true;}return false;}virtual void Show2() {cout show2 endl;}virtual void Show1() {}virtual void Show3() {}
};// 框架
// 模板方法模式
class ZooShowEx10 : public ZooShow {
protected:virtual void Show0() {if (! expired) {return true;}return false;}
}class ZooShowEx1 : public ZooShow {
protected:virtual bool Show0() {cout ZooShowEx1 show0 endl;if (! expired) { // 里氏替换return true;}return false;}virtual void Show2(){cout show3 endl;}
};class ZooShowEx2 : public ZooShow {
protected:virtual void Show1(){cout show1 endl;}virtual void Show2(){cout show3 endl;}
};class ZooShowEx3 : public ZooShow {
protected:virtual void Show1(){cout show1 endl;}virtual void Show3(){cout show3 endl;}virtual void Show4() {//}
};
/*
*/
int main () {ZooShow *zs new ZooShowEx10; // 晚绑定还是早绑定// ZooShow *zs1 new ZooShowEx1;// ZooShow *zs2 new ZooShowEx2;zs-Show();return 0;
}
符合那些原则
单一职责 开闭 依赖倒置
子类扩展时需要依赖基类的虚函数实现使用者只依赖接口
封装变化点protected 接口隔离 最小知道原则 对于用户我们只需要知道show()然后zs-show()就可以了。
如何扩展
也就是这一块
class ZooShowEx1 : public ZooShow {
protected:virtual bool Show0() {cout ZooShowEx1 show0 endl;if (! expired) { // 里氏替换return true;}return false;}virtual void Show2(){cout show3 endl;}
};实现子类继承基类复写子流程 通过多态调用方式使用
总结
要点
最常用的设计模式子类可以复写父类子流程使父类的骨架流程丰富反向控制流程的典型应用父类 protected 保护子类需要复写的子流程这样子类的子流程只能父类来调用
本质 通过固定算法骨架来约束子类的行为 结构图
设计模式-观察者模式
定义
对象间的一种一对多变化的依赖关系以便当一个对象(Subject)的状态发生改变时所有依赖于它的对象都得到通知并自动更新。 ——《 设计模式》 GoF
解决问题
稳定性“—”对“多”的依赖关系“一”变化“多”跟着变化
变化点“多”增加“多”减少
代码结构
背景 气象站发布气象资料给数据中心数据中心经过处理将气象信息更新到两个不同的显示终端A 和B一是数据中心的数据多是所有的中断的数据都要变化
没有使用设计模式的时候问题就是每次增加终端都要修改代码 class DisplayA {
public:void Show(float temperature);
};class DisplayB {
public:void Show(float temperature);
};class DisplayC {
public:void Show(float temperature);
}class WeatherData {
};class DataCenter {
public:void TempNotify() {DisplayA *da new DisplayA;DisplayB *db new DisplayB;DisplayC *dc new DisplayC;// DisplayD *dd new DisplayD;float temper this-CalcTemperature();//计算数据da-Show(temper);//跟新数据db-Show(temper);dc-Show(temper);dc-Show(temper);//问题就是每次增加终端都要修改代码}
private:float CalcTemperature() {WeatherData * data GetWeatherData();// ...float temper/* */;return temper;}WeatherData * GetWeatherData(); // 不同的方式
};int main() {DataCenter *center new DataCenter;//数据中心center-TempNotify();return 0;
}使用设计模式具体中断的改变不能影响我们的接口。应对稳定点抽象。应对变化点扩展继承和组合 对于一对多一就是DataCenter而多就是在DataCenter中定义一个list。
// 应对稳定点抽象
// 应对变化点扩展继承和组合
class DataCenter {//一
public:void Attach(IDisplay * ob) {//增加终端用户可以加入//}void Detach(IDisplay * ob) {//减少终端//}void Notify() {//数据变化通知各个终端一变化多就变化float temper CalcTemperature();for (auto iter : obs) {iter.Show(temper);}}// 接口隔离
private:WeatherData * GetWeatherData();float CalcTemperature() {WeatherData * data GetWeatherData();// ...float temper/* */;return temper;}std::listIDisplay* obs;//终端这个就是多
};完整代码
#include list
#include algorithm
using namespace std;
//
class IDisplay {//显示每一个终端
public:virtual void Show(float temperature) 0;virtual ~IDisplay() {}
};class DisplayA : public IDisplay {
public:virtual void Show(float temperature) {cout DisplayA Show endl;}
private:void jianyi();
};class DisplayB : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayB Show endl;}
};class DisplayC : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayC Show endl;}
};class DisplayD : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayC Show endl;}
};class WeatherData {
};// 应对稳定点抽象
// 应对变化点扩展继承和组合
class DataCenter {
public:void Attach(IDisplay * ob) {//增加终端用户可以加入//}void Detach(IDisplay * ob) {//减少终端//}void Notify() {//数据变化通知各个终端float temper CalcTemperature();for (auto iter : obs) {iter.Show(temper);}}// 接口隔离
private:WeatherData * GetWeatherData();float CalcTemperature() {WeatherData * data GetWeatherData();// ...float temper/* */;return temper;}std::listIDisplay* obs;//终端
};int main() {// 单例模式DataCenter *center new DataCenter;// ... 某个模块实际上都是在其他文件中IDisplay *da new DisplayA();center-Attach(da);// ...实际上都是在其他文件中IDisplay *db new DisplayB();center-Attach(db);实际上都是在其他文件中IDisplay *dc new DisplayC();center-Attach(dc);center-Notify();//-----center-Detach(db);center-Notify();//....center-Attach(dd);center-Notify();return 0;
}补充单例Singleton模式的定义指一个类只有一个实例且该类能自行创建这个实例的一种模式。
符合哪些设计原则
面向接口编程 接口隔离
类与类依赖在一个接口就是那个list容器存储接口
封装变化点
attach增加终端detach减少终端
如何扩展
继承实现接口 调用attach 调用detach 就是这样
class DisplayD : public IDisplay{
public:virtual void Show(float temperature) {cout DisplayC Show endl;}
};center-Attach(dd);center-Notify();总结
要点
观察者模式使得我们可以独立地改变目标与观察者从而使二者之间的关系松耦合观察者自己决定是否订阅通知目标对象并不关注谁订阅了观察者不要依赖通知顺序目标对象也不知道通知顺序常用在基于事件的ui框架中也是 MVC 的组成部分常用在分布式系统中、actor框架中 本质 触发联动 结构图
设计模式-策略模式
定义
定义一系列算法把它们一个个封装起来并且使它们可互相替换。该模式使得算法可独立于使用它的客户程序而变化。——《设计模式》 GoF
解决问题
稳定点
客户程序与算法的调用关系
变化点
新加算法算法内容改变
客户只需要调用就行不需要知道那个算法
代码结构
某商场节假日有固定促销活动为了加大促销力度现提升国庆节促销活动规格稳定点就是这个促销活动改变点就是这些具体的活动折扣啥的。 也就是策略模式用来消除if-else 没有设计模式的代码
enum VacationEnum {VAC_Spring,VAC_QiXi,VAC_Wuyi,VAC_GuoQing,VAC_ShengDan,
};class Promotion {VacationEnum vac;
public:double CalcPromotion(){if (vac VAC_Spring {// 春节}else if (vac VAC_QiXi) {// 七夕}else if (vac VAC_Wuyi) {// 五一}else if (vac VAC_GuoQing) {// 国庆}else if (vac VAC_ShengDan) {}}};加人了设计模式 其中 稳定点抽象去解决它调用关系 变化点扩展继承和组合去解决它
class Context {};// 稳定点抽象去解决它
// 变化点扩展继承和组合去解决它
class ProStategy {
public:virtual double CalcPro(const Context ctx) 0;virtual ~ProStategy();
};
// cpp
class VAC_Spring : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};
// cpp
class VAC_QiXi : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};
class VAC_QiXi1 : public VAC_QiXi {
public:virtual double CalcPro(const Context ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};class VAC_Shengdan : public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};class Promotion {
public:Promotion(ProStategy *sss) : s(sss){}~Promotion(){}double CalcPromotion(const Context ctx){return s-CalcPro(ctx);}
private:ProStategy *s;//这就是一种依赖注入的方式
};int main () {Context ctx;ProStategy *s new VAC_QiXi1();Promotion *p new Promotion(s);p-CalcPromotion(ctx);return 0;
}设计原则
接口隔离
依赖注入(*s就是依赖注入)class Promotion {
public:Promotion(ProStategy *sss) : s(sss){}~Promotion(){}double CalcPromotion(const Context ctx){return s-CalcPro(ctx);}
private:ProStategy *s;//依赖注入的方式
};解决通过一个接口解决两个类的依赖
面向接口编程 开闭原则
如何扩展代码
写一个接口然后依赖注入的方式调用它
class VAC_QiXi1: public ProStategy {
public:virtual double CalcPro(const Context ctx){}
};Context ctx;ProStategy *s new VAC_QiXi1();Promotion *p new Promotion(s);p-CalcPromotion(ctx);总结
要点
策略模式提供了一系列可重用的算法从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换策略模式消除了条件判断语句也就是在解耦合
本质 分离算法选择实现 结构图