创建型设计模式学习笔记
简述
设计模式是指在软件开发中,经过验证的,用于解决在特定环境下重复出现的、特定问题的解决方案。
有创建型和结构型设计模式
怎么学习设计模式
- 找稳定点和变化点,把变化点隔离出来,也就是解耦合(注意不是消除耦合)
- 先满足设计原则,慢慢迭代出设计模式
耦合表示两个子系统(或类)之间的关联程度
编程在于抽象和分治思维。
设计原则
依赖倒置
- 高层模块不应该依赖于底层模块,两者都应该依赖抽象
- 抽象不应该依赖具体实现,具体实现应该依赖于抽象。(这话是真抽象~~)
开放封闭
- 一个类应该对扩展(组合与继承开放),对修改关闭。
面向接口
- 不将变量类型声明为某个特定的具体类,而是声明为某个接口。
- 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
- 减少系统中各部分的依赖关系,从而实现高内聚、松耦合的类型设计方案。
封装变化点
- 将稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离。
单一职责
- 一个类应该仅有一个引起它变化的原因。
里氏替换
- 子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责。
接口隔离
- 不应该强迫客户依赖于它们不用的方法;
- 一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责
组合优于继承
- 继承耦合度高,组合耦合度低
模板方法
定义:
定义一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。 Template Method使得子类可以不
改变一个算法的结构即可重定义该算法的某些特定步骤。
例子
某个品牌动物园,有一套固定的表演流程(稳定点),但是其中有若干个表演子流程(变化点)可创新替换,以尝试迭代更新表演流程;
有缺陷的代码:
#if 0
class ZooShow {public:void Show0() {cout << "show0" << endl;}void Show2() {cout << "show2" << endl;}
};class ZooShowEx {public:void Show1() {cout << "show1" << endl;}void Show3() {cout << "show3" << endl;}
};// 不满足单一职责 , 开放扩展封闭修改 原则
// 动物园固定流程,迭代创新
// 稳定和变化 一定的方向上变化
#else if 2
class ZooShow {public:ZooShow(int type = 1) : _type(type) {}public:void Show() {if (Show0())PlayGame(); // 里氏替换Show1();Show2();Show3();}// 接口隔离 不要让用户去选择它们不需要的接口
private:void PlayGame() {cout << "after Show0, then play game" << endl;}private:bool Show0() {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;
};#endifint main () {#if 0ZooShow *zs = new ZooShow;ZooShowEx *zs1 = new ZooShowEx;zs->Show0();zs1->Show1();zs->Show2();zs1->Show3();
#else if 2ZooShow *zs = new ZooShow(1);zs->Show();
#endifreturn 0;
}
优化后的代码
class ZooShow {public:void Show() {if (Show0())PlayGame();Show1();Show2();Show3();}private:void PlayGame() {cout << "after Show0, then play game" << endl;}protected:virtual bool Show0(){cout << "show0" << endl;return true;}virtual void Show2(){cout << "show2" << endl;}virtual void Show1() {}virtual void Show3() {}
};
//重写父类的方法
class ZooShowEx1 : public ZooShow {protected:virtual bool Show0(){cout << "show1" << endl;return true;}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 ZooShowEx3;// ZooShow *zs1 = new ZooShowEx1;// ZooShow *zs2 = new ZooShowEx2;zs->Show();return 0;
}
要点
- 常用的设计模式,子类可以复写父类子流程,使父类的骨架流程丰富;
- 反向控制流程的典型应用;
- 模板方法是最能体现设计模式的精髓,使用频率最高。
- 父类protected保护子类需要复写的子流程,这样子类的子流程只能父类调用
本质
通过固定算法骨架来约束子类的行为。
注解:
单一职责、里氏替换、接口隔离都是来佐证开闭原则
里氏替换:开放扩展,继承父类的职责单一职责:对修改封闭
接口隔离:对修改封闭
观察者模式
定义:
定义对象间的一种一对多(变化)的依赖关系,以便一个对象(subject)的状态发生改变时,所有依赖于它的对象都能得到通知并自动更新
例子:
气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到两个不同的显示终端(A和B);
即数据中心接收到数据(信号),就要进行处理并发送给所有终端(槽函数)
满足观察者模式的demo
class IDisplay {public:virtual void Show(float temperature) = 0;virtual ~IDisplay() {}
};class DisplayA : public IDisplay {public:virtual void Show(float temperature);
private:void jianyi();
};class DisplayB : public IDisplay{public:virtual void Show(float temperature);
};class DisplayC : public IDisplay{public:virtual void Show(float temperature);
};class WeatherData {};class DataCenter {public:void Attach(IDisplay * ob);void Detach(IDisplay * ob);void Notify() {float temper = CalcTemperature();for (auto iter = obs.begin(); iter != obs.end(); iter++) {(*iter)->Show(temper);}}// 接口隔离
private:virtual WeatherData * GetWeatherData();virtual float CalcTemperature() {WeatherData * data = GetWeatherData();// ...float temper/* = */;return temper;}//存放订阅者(观察者)std::vector<IDisplay*> obs;
};int main() {DataCenter *center = new DataCenter;IDisplay *da = new DisplayA();IDisplay *db = new DisplayB();IDisplay *dc = new DisplayC();//"订阅"center->Attach(da);center->Attach(db);center->Attach(dc);//"发布"center->Notify();//-----center->Detach(db);center->Notify();return 0;
}
要点
- 观察者模式使得我们可以独立地改变目标与观察者,从而使二者之间的关系松耦合
- 观察者自己决定是否订阅通知,目标对象并不关注谁订阅了。
- 观察者不要依赖通知顺序,目标对象也不知道通知顺序
- 常用在基于事件的ui框架中,也是MVC的组成部分;
- 常用在分布式系统中、actor框架中。
观察者模式还用在:zk、etcd、kafka、redis、分布式锁、
公平锁(互斥锁、会阻塞导致线程切换)、
非公平锁(自旋锁)
队列操作:用自旋锁
重io操作(磁盘操作、关闭大文件):用互斥锁
锁粒度: 操作临界资源的时长
本质:触发联动
结构图
心得
- 学了信号槽、以及C语言中信号注册回调函数知识,使得这里观察者模式的理解柳暗花明。
策略模式
定义
定义一系列算法,把它们一个个封装起来,并使它们可以相互替换。该模式使得算法可独立于使用它的客户程序而变化。
背景
某商场节假日有固定促销活动,为了加大销售力度,现提升国庆节促销活动规格。
未使用策略模式的代码
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) {}}};
如果一个 只有稳定点 不需要设计模式
如果 全是变化点 怎么办? 如 c++ 游戏开发 ,则使用脚本语言
采用策略模式的代码
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;
}
在时间判断中,时间if else 判断是否是某个节日----稳定点
根据节日,使用if else选择某个促销规格----变化点
要点
- 策略模式提供了一系列可重用的算法,从而使得类型在运行时方便地根据需要在各个算法之间切换。
- 策略模式消除了条件判断语句;也就是在解耦合。
本质
- 分离算法,选择实现
结构图
创建型设计模式学习笔记相关推荐
- JavaScript设计模式读书笔记(一)= 创建型设计模式
全系列目录 JavaScript设计模式读书笔记(一)=> 创建型设计模式 JavaScript设计模式读书笔记(二)=> 结构型设计模式 JavaScript设计模式读书笔记(三)=&g ...
- 从框架源码中学习创建型设计模式
文章目录 从框架源码中解读创建型设计模式 工厂模式 案例一:RocketMQ源码-创建Producer生产者 案例二:RocketMQ源码-创建过滤器工厂 抽象工厂 案例一:Dubbo源码-创建缓存的 ...
- java/android 设计模式学习笔记(1)--- 单例模式
前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...
- 设计模式学习笔记清单
设计模式学习笔记清单 关于设计模式许多人已经耳熟能详,这段时间结合李建忠的教学视频以及大量网络资料,把这部分过了一遍,整理出学习笔记,而真正的深入学习和理解只能在具体的开发环境中日积月累. ...
- 步步为营 .NET 设计模式学习笔记系列总结
设计模式我从开篇到23种设计模式的讲解总共花了进两个月的时间,其间有很多读者给我提出了很好的建议,同时也指出了我的不足,对此我表示感谢,正是由于很多读者的支持我才能坚持的写到最后.在此表示我真诚的谢意 ...
- 设计模式学习笔记-2 创建者模式-工厂方法模式
设计模式学习笔记-2 创建者模式-工厂方法模式 工厂模式介绍 工厂模式又称工厂方法模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型. 这种设计模式使Java开 ...
- 创建型设计模式(待更新)
前言 - 熟能生巧(★★★) 关于设计模式的学习,需要结合具体的应用场景进行理解,即站在用户的角度去理解需求,目的是让自己设计的代码能够为用户提供统一的接口,并且设计的模块具有高内聚低耦合.有更好的可 ...
- 设计模式学习笔记(C#版)
目录 系列文章目录 前言 1.设计模式的6大原则 1.开闭原则 2.单一职责原则 3.迪米特法则(最少知道原则) 4.里氏代换原则 5.依赖倒转原则 6.接口隔离原则 2.设计模式(创建型) 1.单例 ...
- 36设计模式学习笔记
设计模式学习笔记 文章目录 0.设计模式简介 1.单例模式 2.工厂方法 3.抽象工厂 4.责任链模式 5.模板方法 ok 一.模板方法简介 二.模式的定义和特点 三.模式的结构和实现 四.什么是模板 ...
最新文章
- 学习html5系列之比较典型的div滥用
- Linux下查看Go语言软件运行情况
- 河北计算机科学与技术研究生,2021年河北工业大学计算机科学与技术(081200)硕士研究生招生信息_考研招生计划和招生人数 - 学途吧...
- java 自动启动监听_Spring Boot 启动事件和监听器,太强大了!
- Spring Boot 动态修改定时任务cron参数
- pythonrandint函数左闭右开_Python容器类型公共方法总结
- 燃料电池厂商的市场竞争
- java attributes用法_C#中的Attributes的用法
- 安卓webview开发简介
- QT_kvaser动态链接库配置
- 差距几何 Vista与XP系统性能对比测试(下)
- Flask:工厂函数和蓝本
- Android MVP 架构设计 (一)
- 计算机一些专业术语,计算机专业术语大全
- 优麒麟mysql_ubuntu 优麒麟下mysql5.7root密码的重置
- matlab错误使用meshline47,matlab里mesh出错Z 必须为矩阵,不能是标量或矢量怎么解决...
- 数据分析案例-四川省旅游景点数据分析
- LDO稳压器工作原理
- AI:2023年6月9日北京智源大会演讲分享之基础模型前沿技术论坛—《工程化打造AI中的CPU》、《构建一个AI系统:在LLM上应用带有RLHF来推进定制》、《多模态预训练的进展回顾与展望》、《扩展大
- ALS冰桶挑战案例详解
热门文章
- 大战AV终结者(三)。。激战
- 适合运动时戴的耳机有哪些?五款运动耳机挑选推荐
- JAVA转义字符的使用
- 利用百度地图获取地市镇区边界
- 活动 | 21天简笔画训练营,我想对你说……
- MySQL 使用Navicat生成数据字典方法(非常详细)
- 爬虫抓取网易云音乐民谣歌单,收听量排行
- 2018.12.10 第4题:定义两个类,描述如下: [必做题] 4.1定义一个人类Person: 4.1.1定义一个方法sayHello(),可以向对方发出问候语“hello,my name is
- 【新书推荐】【2018.07】数字化战争
- 王者服务器维护7月九号,7月9日王者荣耀ios服务器维护中 王者ios服务器维护到几点?...