简述

  1. 设计模式是指在软件开发中,经过验证的,用于解决在特定环境下重复出现的、特定问题的解决方案。

  2. 创建型结构型设计模式

  3. 怎么学习设计模式

    1. 稳定点和变化点,把变化点隔离出来,也就是解耦合(注意不是消除耦合)
    2. 先满足设计原则,慢慢迭代出设计模式
  4. 耦合表示两个子系统(或类)之间的关联程度

  5. 编程在于抽象和分治思维。

设计原则

依赖倒置

  • 高层模块不应该依赖于底层模块,两者都应该依赖抽象
  • 抽象不应该依赖具体实现,具体实现应该依赖于抽象。(这话是真抽象~~)

开放封闭

  • 一个类应该对扩展(组合与继承开放),对修改关闭。

面向接口

  • 不将变量类型声明为某个特定的具体类,而是声明为某个接口
  • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
  • 减少系统中各部分的依赖关系,从而实现高内聚、松耦合的类型设计方案。

封装变化点

  • 稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离。

单一职责

  • 一个类应该仅有一个引起它变化的原因。

里氏替换

  • 子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责

接口隔离

  • 不应该强迫客户依赖于它们不用的方法;
  • 一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责

组合优于继承

  • 继承耦合度高,组合耦合度低

模板方法

定义:

定义一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。 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选择某个促销规格----变化点

要点

  • 策略模式提供了一系列可重用的算法,从而使得类型在运行时方便地根据需要在各个算法之间切换
  • 策略模式消除了条件判断语句;也就是在解耦合。

本质

  • 分离算法,选择实现

结构图

创建型设计模式学习笔记相关推荐

  1. JavaScript设计模式读书笔记(一)= 创建型设计模式

    全系列目录 JavaScript设计模式读书笔记(一)=> 创建型设计模式 JavaScript设计模式读书笔记(二)=> 结构型设计模式 JavaScript设计模式读书笔记(三)=&g ...

  2. 从框架源码中学习创建型设计模式

    文章目录 从框架源码中解读创建型设计模式 工厂模式 案例一:RocketMQ源码-创建Producer生产者 案例二:RocketMQ源码-创建过滤器工厂 抽象工厂 案例一:Dubbo源码-创建缓存的 ...

  3. java/android 设计模式学习笔记(1)--- 单例模式

    前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...

  4. 设计模式学习笔记清单

    设计模式学习笔记清单 关于设计模式许多人已经耳熟能详,这段时间结合李建忠的教学视频以及大量网络资料,把这部分过了一遍,整理出学习笔记,而真正的深入学习和理解只能在具体的开发环境中日积月累.      ...

  5. 步步为营 .NET 设计模式学习笔记系列总结

    设计模式我从开篇到23种设计模式的讲解总共花了进两个月的时间,其间有很多读者给我提出了很好的建议,同时也指出了我的不足,对此我表示感谢,正是由于很多读者的支持我才能坚持的写到最后.在此表示我真诚的谢意 ...

  6. 设计模式学习笔记-2 创建者模式-工厂方法模式

    设计模式学习笔记-2 创建者模式-工厂方法模式 工厂模式介绍 工厂模式又称工厂方法模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型. 这种设计模式使Java开 ...

  7. 创建型设计模式(待更新)

    前言 - 熟能生巧(★★★) 关于设计模式的学习,需要结合具体的应用场景进行理解,即站在用户的角度去理解需求,目的是让自己设计的代码能够为用户提供统一的接口,并且设计的模块具有高内聚低耦合.有更好的可 ...

  8. 设计模式学习笔记(C#版)

    目录 系列文章目录 前言 1.设计模式的6大原则 1.开闭原则 2.单一职责原则 3.迪米特法则(最少知道原则) 4.里氏代换原则 5.依赖倒转原则 6.接口隔离原则 2.设计模式(创建型) 1.单例 ...

  9. 36设计模式学习笔记

    设计模式学习笔记 文章目录 0.设计模式简介 1.单例模式 2.工厂方法 3.抽象工厂 4.责任链模式 5.模板方法 ok 一.模板方法简介 二.模式的定义和特点 三.模式的结构和实现 四.什么是模板 ...

最新文章

  1. 学习html5系列之比较典型的div滥用
  2. Linux下查看Go语言软件运行情况
  3. 河北计算机科学与技术研究生,2021年河北工业大学计算机科学与技术(081200)硕士研究生招生信息_考研招生计划和招生人数 - 学途吧...
  4. java 自动启动监听_Spring Boot 启动事件和监听器,太强大了!
  5. Spring Boot 动态修改定时任务cron参数
  6. pythonrandint函数左闭右开_Python容器类型公共方法总结
  7. 燃料电池厂商的市场竞争
  8. java attributes用法_C#中的Attributes的用法
  9. 安卓webview开发简介
  10. QT_kvaser动态链接库配置
  11. 差距几何 Vista与XP系统性能对比测试(下)
  12. Flask:工厂函数和蓝本
  13. Android MVP 架构设计 (一)
  14. 计算机一些专业术语,计算机专业术语大全
  15. 优麒麟mysql_ubuntu 优麒麟下mysql5.7root密码的重置
  16. matlab错误使用meshline47,matlab里mesh出错Z 必须为矩阵,不能是标量或矢量怎么解决...
  17. 数据分析案例-四川省旅游景点数据分析
  18. LDO稳压器工作原理
  19. AI:2023年6月9日北京智源大会演讲分享之基础模型前沿技术论坛—《工程化打造AI中的CPU》、《构建一个AI系统:在LLM上应用带有RLHF来推进定制》、《多模态预训练的进展回顾与展望》、《扩展大
  20. ALS冰桶挑战案例详解

热门文章

  1. 大战AV终结者(三)。。激战
  2. 适合运动时戴的耳机有哪些?五款运动耳机挑选推荐
  3. JAVA转义字符的使用
  4. 利用百度地图获取地市镇区边界
  5. 活动 | 21天简笔画训练营,我想对你说……
  6. MySQL 使用Navicat生成数据字典方法(非常详细)
  7. 爬虫抓取网易云音乐民谣歌单,收听量排行
  8. 2018.12.10 第4题:定义两个类,描述如下: [必做题] 4.1定义一个人类Person: 4.1.1定义一个方法sayHello(),可以向对方发出问候语“hello,my name is
  9. 【新书推荐】【2018.07】数字化战争
  10. 王者服务器维护7月九号,7月9日王者荣耀ios服务器维护中 王者ios服务器维护到几点?...