设计模式

c#

Posted by Jow on August 21, 2019

目录

  1. 总览
  2. 简单工厂模式
  3. 策略模式
  4. 单一职责原则
  5. 依赖倒转原则
  6. 装饰模式
  7. 代理模式
  8. 工厂方法模式
  9. 原型模式
  10. 模板方法
  11. 迪米特法则
  12. 外观模式
  13. 建造者模式
  14. 适配器模式
  15. 备忘录模式
  16. 组合模式
  17. 迭代模式
  18. 单例模式
  19. 桥接模式
  20. 命令模式
  21. 责任链模式
  22. 访问模式
  23. 状态模式

有机会就尝试一下,这样你才知道自己究竟几斤几两。

总览

这 7 种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。

  1. 开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;
  2. 里氏替换原则告诉我们不要破坏继承体系;注意继承的使用
  3. 依赖倒置原则告诉我们要面向接口编程;高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象
  4. 单一职责原则告诉我们实现类要职责单一;提高内聚,减少耦合,一个类只负责一项职责
  5. 接口隔离原则告诉我们在设计接口的时候要精简单一;臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
  6. 迪米特法则告诉我们要降低耦合度;只和你的朋友交谈,不跟陌生人交谈
  7. 合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。 _____ 创造模式:

  8. 单例:singleton
  9. 原型:对自己的克隆
  10. 工厂方法
  11. 抽象工厂
  12. 建造者: Director Product Builder ConcreteBuilder __ 结构性模式

  13. 代理模式
  14. 适配器模式
  15. 桥接模式
  16. 装饰模式
  17. 外观模式
  18. 享元模式
  19. 组合模式

行为型模式

  1. 模板方法
  2. 策略模式
  3. 命令模式
  4. 职责链模式
  5. 状态模式
  6. 观察模式
  7. 中介模式
  8. 迭代器模式
  9. 访问模式
  10. 备忘录模式
  11. 解释器模式

简单工厂模式 创造性模式

例子 :计算器:

运算基本: 继承运算基本类的具体计算类来实现加法、减法、乘法等等。

运算类工厂:根据传递过来的操作符进行运算类的构造然后返回集体的运算结果 。

必要类: 基本类、继承基本类的具体类、以调用那个具体类的工厂、会使用switch函数。

在必要的时候,可以通过配置文件动态的获取需要的具体类。

策略模式 行为型模式

例子:商场打折

打折基本类 、不同打折规则的具体类;例如打几折、满减等

context关联具体的策略 然后进行调用

context上下文 用一个具体的策略来配置保持对它的引用 在构造函数中初始化,引用具体策略类

在打折的context中 可以结合工厂模式 使用switch 传入type来引用具体的策略 别忘记将方法也封装到context类中

策略模式和简单工厂模式很像但还是存在区别的

  • 用途不同 工厂是创建型模式,他的作用就是创建对象

策略是行为型模式,它的作用是一个对象在许多行为中选择一种行为,这些行为是可以相互替换的

  • 关注点不同 一个关注对象的创建

一个关注行为的封装

  • 解决不同的问题 工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。

策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。

  • 工厂相当于黑盒子,策略相当于白盒子;

例子如上:计算器的关注点在应用不同的计算规则 计算规则的创建 。打折在于选择不同的打折规则,他们是可以相互替换的

单一职责原则

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

例子: 俄罗斯方块 一个n维数组,有方块填充变成1,无方块变成0,使用指针进行帧更新

依赖倒转原则

高层模块不应该依赖底层模块 两个都应该依赖抽象

抽象不应该依赖与细节 细节应该依赖于抽象

针对于接口编程,不要针对于实现编程

里氏代换原则:子类必须能够替换掉它们的父类型 只有子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能在父类的基础上增加新的行为。

针对于抽象编程而不是细节 程序中所有的依赖关系终止于抽象或者接口,那就是面向对象的设计,反之那就是过程化设计

装饰模式 结构型模式

动态给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加的灵活。

装饰模式利用设置组件来对对象进行封装,这样每个装饰对象的实现和如何使用这个对象分离开来,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链中。

baseComponent -> concreteComponent -> decorator 继承关系

baseComponent -> decorator -> concreteDerorator 继承关系

baseComponent concreteComponent decorator有操作函数

concreteDerorator 多个行为方法

人穿衣服

baseComponent名字和说出自己的名字

人 component

衣服 装饰 component 有一个装饰方法 记录装饰的组件

具体衣服 装饰

代理模式

代理模式:为其他对象提供一种代理以控制对这个对象的访问

代理商和物主需要用统一接口链接 代理商帮物主做物主想做的事情

代理帮别人送礼物

行为 花 书 贺卡 这些是接口 代理和物主都要拥有

追求者 代理 被追求者

追求者(被追求者)

代理(被追求者) 代理里面组合追求者 执行追求者的行为

工厂方法模式

把简单工厂分割开来一个算法行成一个工厂 这样分支判断就不在简单工厂当中了而是在客户端当中

IFactory -> 加法工厂 等等

客户端调用方法

new 对应的工厂 然后调用create方法创建具体的对象

原型模式

用原型实例制定创建对象的种类,并通过拷贝这些原型创建新的对象

即在对象中放置一个深拷贝方法 用来返回新的对象实例 在Java中clone() 就是深拷贝

!attention

如果类中有自定义类 也要在自定义类中进行cloneable接口的引用

而且在聚合类的clone函数中进行调用赋值

基本数据类型会进行深拷贝

模板方法

定义一个操作中的算法骨架,而将一些不走延迟刀子类中。模板方法使得子类可以不改变一个算法的结构即可以重定义该算法的某些特定步骤。

选择题 每个人都做除了答案不同其它都一样

所以将获取答案的方法提炼出来形成抽象函数 有子类进行填充

function question() answer + getAnswer()

abstract function getAnswer() return “a”

将一些方法下放到子类中进行实现

迪米特法则

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

外观模式

为子系统中的一组接口提供一个一致的界面,次莫属定义了一个高层接口,这个接口是的这一子系统更加容易使用。

facede类 关联各个子系统 然后实现不同方法来表现不同子系统想在特定情况想要表现出来的

用法:

  1. 设计初期阶段,注意有意识的讲不通的两个层分离,层与层之间建立外观facade
  2. 开发阶段,子系统往往因为不断的重构演化而变得越来越复杂。增加facade可以提供简单的接口,减少他们之间的依赖。
  3. 在维护一个大型遗留系统的时候,当旧系统已经非常难以扩展的时候,为新系统开发一个新的外观类,来提供设计粗糙或高复杂的遗留代码的比较简单清晰简单接口。

建造者模式

builder -> concreteBuilder director product

director 指挥建造者生产产品 然后不同的生产者针对自己要做的产品添加组件组装产品

观察者模式

数据发生变化 通知视图层更新界面 这就是观察者模式

在游戏中事件的添加和管理就是明显观察者模式的应用 Java可以直接调用观察者模式

Java中有观察者模式的接口 observer 接口是观察者 Observable 是被观察者 注意数据改变要调用setChanged这样你通知才能改变数据

抽象工厂模式

抽象工厂模式在工厂方法模式的基础上在具体的工厂里面添加属于其属性的工厂 组成工厂组 用来替换

数据库的替换 操作不同在操作哪里构造工厂,将各种操作放在工厂里作为集合传递出来

抽象工厂模式不在像工厂模式那样,一个对象一个工厂,而是一组对象一个具体的工厂。

状态模式

状态模式,对一个队形的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

工作与状态 每个人在不同时间段的状态

适配器模式

将一个类的接口转换成客户希望的另一个接口。adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

外籍球员和本土球员 布置战术翻译需要将战术翻译给外籍球员

所以在交流方面 外籍球员还要依赖一层翻译

备忘录模式

游戏角色 角色状态存储箱 角色状态管理者

组合模式

即树状图 从root开始 每个节点都有父节点和子节点 一层一层

迭代器模式

提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露该对象的内部表示

售票员和乘客 乘客是聚集类 售票员作为迭代器 聚集类聚合迭代器

list 即是迭代器模式

单列模式

在程序中有且只存在这一个实例

使用静态记录自身是否被实例化过 没有实例化 有直接调用

还有多线程的单列模式记得加锁 同步

加锁保证一个县城位于代码的临界区时,另一个线程不进入临界区。

桥接模式

合成/聚合复用原则

尽量使用聚合和组合 而不是使用继承

将抽象部分与它的实现部分分离,使他们都可以独立的变化

具体实例化角色 和 扩展实例化角色

扩展实例化角色组合具体实例化角色

手机 不同的手机品牌 扩展实例化角色

游戏 同一游戏不同平台 具体实例化角色

手机组合游戏 让这款游戏可以在手机上完

命令模式

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

厨师和服务员

责任链模式

为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;

当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

状态模式

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,

允许状态对象在其内部状态发生改变时改变其行为。

访问者模式

用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用

于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。

它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。

访问者模式包含以下主要角色。

  1. 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
  2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  3. 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  4. 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
  5. 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

review

  1. 建造者模式:director product builder concreteBuilder,

指挥管负责指挥建造者 product中有各种组件和呈现自己的方法 建造者组成组件之后返回产品

product: setPart1 setPart2 setPart3 show 方法 builder: buildPart1 buildPart2 buildPart3 returnProduct

ConcreteBuilder: 建造Product

  1. 装饰模式 :传递的式的装扮 耦合下一个执行的组件