设计理念
高内聚,低耦合
模块:模块是按业务系统划分,可以颗粒化,方法,类都可以称之为模块。
内聚:泛指模块内的关系
耦合:泛指模块之间的关系
高内聚:模块内尽量以围绕着完成一个具体功能为目的,不涵盖与之没有较大关系的功能方法
低耦合:模块之间的关系不紧密,模块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就是更换策略