设计之路

设计理念

高内聚,低耦合

  模块:模块是按业务系统划分,可以颗粒化,方法,类都可以称之为模块。

  内聚:泛指模块内的关系

  耦合:泛指模块之间的关系  

高内聚:模块内尽量以围绕着完成一个具体功能为目的,不涵盖与之没有较大关系的功能方法

低耦合:模块之间的关系不紧密,模块A改变的同时不会影响到关联模块B,反之,如果有个10个模块,修改了1个模块,另外9个模块也要跟着改,这就属于高耦合

OO三大特性

封装,继承,多态

封装:把客观事物封装成一个对象,对象可以保留隐私信息,并且可以暴露某些信息【公有方法,属性】给可信赖用户

继承:对象之间可以互相继承,被继承者称之为父类,继承者称为子类,子类会继承父类的公有方法【含保护级,*无需编写代码就可以扩展获得某些功能】

多态:一个类实例的相同方法在不同情境下会有不同的结果,多用于继承+虚方法

  如:假设有个抽象类bird,有个虚方法fly,具体实现类hawk,sparrow分别继承于bird,重写fly方法,它们二者的fly方法是不一样的

其他:重写,重载

重写:父类有个虚方法,子类继承重写

重载:函数名称一样,但传入参数不一样【也可以返回参数不一样】

  如:构造函数重载

UML类关系

继承,依赖,关联,聚合,组合

继承是类与类【接口】之间的常见关系,子类继承父类所有功能,并可以扩展新功能

依赖是类A使用了类B,这种关系是临时、弱的,用完就舍弃,类A使用了类B之后,类B的生命周期就已经结束

  通常是类A里面的某个方法【也可以是构造函数】用到类B的某个属性或者方法

关联是强依赖,这种关系是持久的,只要类A在,类B就一直存在

  通常是类A里面有类B的实例【类A里面有个属性是类B】

聚合是关联的一种,体验在真实场景下,表达的是一种has-a的关系,A和B各自有独立的生命周期,如公司与员工,计算机与CPU

组合也是关联的一种,表达的是一种contains-a的关系,有A才有B,没A就没B,如人与手

设计原则

SRP:单一职责原则

  对一个类而言,引起其变化的原因应该只有一个,换种说法就是这个类只负责干一件事【内聚】

DIP:依赖倒置原则

  抽象不应该依赖细节,细节应该依赖抽象,有点绕口,本质就是面向接口编程,而不是面向实现编程

  如:以电脑主板为例,主板会预留一些插槽【接口】,显卡,内存条按照插槽规则具体设计【细节】,这样如果一根内存条坏了,只需换一根内存条,而不需要把主板也换了

OCP:开闭原则

  对扩展开发,对修改关闭,即代码每次发生变化时,要通过添加新的代码来增强现有类型的行为,而不是修改原有的代码。

  如:我们的电脑主板,可以插显卡,内存条,CPU等等,主板就是对扩展【插内存条,插显卡】开放,对修改关闭,这种实现也可理解为面向改变的提出来当公共接口,外部扩展都与这个公共接口通信

LSP:里氏替换原则

  子类能够完全替换父类,父类所有动作,子类都能完成

  如:企鹅继承鸟,鸟能飞,但企鹅不能飞,这就违反里氏替换原则

Lod:迪米特原则【最少知识原则】

  换个说法就是不跟陌生人说话,就是2个类之间不直接通信,通过第三方转发

  如:我们电脑坏了,我们不会找小王,而是直接找IT部【第三方】,由IT部转发命令给小王修
外观模式、中介者模式使用到

ISP:接口隔离原则

  单个接口不要承担过多的业务,如业务过多,可分离出多个接口来实现,其实就是对单个接口来说,尽量做到单一职责

设计模式

须知

软件产品的本质目标就是要可维护、可扩展、可复用和灵活性好,而设计模式就是为了达到这种设计理念的解决方案,我们可以把设计模式比喻成药【疫苗】,产品当作小动物,只有当动物生病时才吃药【不滥用设计模式】,提前注射疫苗是为了防止以后出问题,想一口气把产品做完美,那是不可能的,市场和客户的需求是不可把控,后期产品的迭代与重构往往更能体现设计模式的好处

种类

设计模式按分类可以分为三种,创建型,结构型,行为型

创建型:创建对象的模式,将客户从所需实例化的对象中解耦,抽象对象实例化的过程

  1:隐藏对象的创建组织过程

  2:封装系统使用的具体类

  • 单件:一个类只有一个实例,提供一个全局访问点
  • 工厂方法:创建单个对象,由子类决定具体要创建的产品
  • 抽象工厂:创建产品家族
  • 建造者:隔离一个产品的具体构造过程
  • 原型:通过克隆或者拷贝实例化对象

结构型:对象和类之间的结构构建关系,把类或对象组合更大的结构中,主要用来处理类或对象的组合,包括类结构型和对象结构型,类结构型就是通过继承实现,对象结构则是通过对象依赖或者关联实现

  • 适配器:封装对象,并提供不同的接口【适配不兼容的接口】
  • 桥接:将产品实现和抽象分离出来
  • 组合:把树结构对象转换成一对一关系【客户用一致的方式处理组合对象和单个对象】
  • 装饰:为对象动态添加职责
  • 外观:简化一群子系统,统一接口访问
  • 享元:某个实例可以共享多次使用
  • 代理:包装对象,以控制对另一个对象的访问

行为型:在不同对象之间划分责任和算法,类和对象如何交互和分配职责。行为模式不仅仅关于类和对象,还关于它们之间的互相作用,简单理解就是对象A关联对象B,对象A执行某个方法A1的同时会影响到B,B可能也会执行某个方法B1

  • 职责链:某个请求需要经过多人处理
  • 命令:封装请求为对象
  • 解释器:系统文法的解释
  • 迭代:在对象的集合中游走,不暴露内部实现
  • 中介者:通过第三方解耦类对象之间的直接交互
  • 备忘录:备份和恢复对象的内部状态
  • 观察者:对象状态改变时动态通知其所有观察者
  • 状态:对象行为改变,其内部状态跟着改变
  • 策略:封装可以互换的算法行为
  • 模板方法:子类决定算法实现的步骤
  • 访问者:在不改变对象的同时增加新的能力

常用模式

创建型

1.抽象工厂

定义:一个工厂产生一组产品,创建一组产品对象

使用频率:高

注意:工厂和产品的关系是一对多,但产品组的数量一定要恒定,如果后期增加一个产品,那么每个工厂都要修改一遍【违背OCP】

,扩展产品组容易,扩展产品组内的产品复杂

UML类图:

2.建造者

定义:把一个产品的创建细节抽离出来,分步实现

使用频率:中低

场景:肯德基霸王套餐【包含鸡腿,饮料,爆米花】,汽车【包含车身,论坛,方向盘等等】

UML类图:

3.工厂方法

定义:一个工厂只能产生一个产品,同理增加一个产品的同时需要增加一个具体工厂

使用频率:高

注意:工厂和产品的关系是一对一,注意简单工厂严格说 不算设计模式,是一种编程习惯。

UML类图:

4.原型

定义:拷贝对象,通常是扩展一个克隆方法

使用频率:中

UML类图:

5.单件

定义:一个类只有一个实例,提供一个全局访问点,如抽象工厂的工厂、对象池【构造器不能公开】

使用频率:中高

UML类图:

 

结构型

6.适配器

定义:转换接口,通过适配器,访问原本访问不了的接口

使用频率:中高

注意:替换之前旧的接口【过期之类】,一般用于开发后期

场景:TypeC充电器,.net中的DataAdapter

UML类图:

7.桥接

定义:分离接口与实现,通常为二维变化

使用频率:中

UML类图:

8.组合

定义:统一接口,通常是把一对多的关系转为一对一的关系,统一接口,呈现的树结构,涵盖叶子节点,用来表达整体与部分的关系

使用频率:中高

场景:winform中的Textbox,Label这种控件类

注意:组合模式是以单一责任设计原则换取透明性【通过让组件的接口含有管理子节点和叶节点的操作,客户可以将组合叶节点一视同仁,这对客户是透明的】

UML类图:

9.装饰

定义:稳定接口,对现有对象增加扩展功能

使用频率:中

UML类图:

10.外观

定义:简化接口,一类子系统封装出一个公共接口出来,外层只与统一通过公共接口打交道,由公共接口决定调取哪个相应子功能

使用频率:高

场景:银行接待,你去银行只要找接待人,他帮你处理贷款,借款等事宜【一般是开发前期】,最少知识原则,只和你的密友谈话

UML类图:

11.享元

定义:保留接口,把一类经常使用的产品对象缓存到一个共享区域,下次调取,就不需要再实例化,直接从缓存区域直接获取就行

使用频率:低

UML类图:

12.代理

定义:假借接口,通过第三方代理访问接口

使用频率:中高

场景:如国内上youtube需要借用VPN,懒加载

UML类图:

 

行为型

13.职责链

定义:封装对象责任,支持责任的变化,构建动态职责连,支持事务型操作,某个行为需要多个对象依次执行,对象直接关系是链式

使用频率:中低

场景:面试(hr-结束-经理),审批

UML类图:

14.命令

定义:解耦请求者与实现者,命令抽象出来,涵盖发送者,命令,接受者,通常命令会与接受者关联起来,发送者可以灵活变化

使用频率:中高

场景:人-遥控器-电视机

UML类图:

15.解释器

定义:注重封装特定领域变化,文法翻译

使用频率:低

场景:字典翻译

UML类图:

16.迭代

定义:注重封装对象集合,不暴露其内部表示,程序可以对对象作遍历操作

使用频率:高

注意:当读取对象的时候不能对对象集合作add,remove影响到集合数的操作

UML类图:

17.中介

定义:解耦对象之间的依赖关系,统一通过第三方建立交互关系

使用频率:中低

场景:聊天室

UML类图:

18.备忘录

定义:注重对象状态变化,支持状态的保持和恢复,记录某个时间点的对象状态,如果有异常,可以执行回滚操作返回到正常状态

使用频率:低

场景:数据库事务日志

UML类图:

19.观察者

定义:注重对象通知变化,通知依赖他的对象更新,涵盖观察者和被观察者,观察者和被观察者关系为多对一,被观察者统一会向观察者发送一个消息,观察者会根据收到的消息作出相应动作【这是一种推的实现】

使用频率:高

场景:订阅,关注微信公众号,股票-股民,红绿灯-司机

UML类图:

20.状态

定义:封装对象与状态的关系,对象的状态会根据对象某个属性变化而变化

使用频率:中

场景:话费(正常-欠费)

UML类图:

21.策略

定义:注重封装算法,随时替换算法

使用频率:中高

场景:排序【快排,2分排序】,税收【上海,南昌】

UML类图:

22.模板方法

定义:封装操作骨架,父类定义好执行步骤,具体实现步骤交给具体子类

使用频率:中

场景:数据库【mysql,oracle,mssql】操作 链接-操作-关闭

注意:钩子是在模板步骤中预先定义一个空方法,由子类继承决定钩子是否使用【步骤是可选的,类似if do】,工厂方法是模板方法的一种特殊版本

UML类图:

23.访问者

定义:注重对象操作变化,运行时为类添加新的操作

使用频率:低

场景:如新来一个邻居,我们去拜访,邻居会有开门,接待,倒水这些相应动作【这些动作一定要恒定】,换个邻居一样是这种操作

注意:多对多【固定数目】的关系,所以要求数据结构相对稳定,增加访问者容易,但数据结构增加一种麻烦就会很麻烦【需改动原有访问者,违反开闭原则】

UML类图:

总结

模式是在某情境下,针对某问题的某种解决方案
情境:应用某个模式的情况,这应该是会不断出现的情况
问题:是你在某情境下达到的目标,但也可以是某情境下的约束
解决方案:就是你追求的,一个通用的设计,用来解决约束、达到目标

设计模式是解决一个经常重复发生的设计问题

尽可能用最简单的方式解决问题【不要写个HelloWorld也要扯上模式】,模式只是一种工具,只有在需要时才用,模式是设计问题的一种解决方案

遵循设计原则,建立最简单的代码完成工作,在这个过程中,看到需要设计模式的地方,才使用模式

当代码有很多if else switch这种条件性的语句时下就可以考虑优化重构代码了

其他

开发注意

  找出会变化的方面,把它们从不变的部分分离出来

  变量不可以有具体类的引用

  不要类派生自具体类【会依赖具体类】

  不要覆盖类中已实现的方法【说明方法不适合继承,没达到共性】

继承是编译时运行,组合【对象关联】则是运行时运行,所以继承趋于稳定,组合则趋于灵活

设计模式固然好,但我们得清楚,设计模式会增加代码复杂度,二维还好,维度越多,耦合越高,可读性越差

MVC是一种复合设计模式【涵盖多个】

V 控件组合模式
M 观察者,模型改变,控制器,视图跟着改变
C 视图和模型策略 换C就是更换策略

原文地址:https://www.cnblogs.com/dalas/p/9516758.html