设计模式¶
为什么使用结构模式¶
如果不采用结构模式的选择的话,当调试某一个复杂的大型类的时候,会发现无法定位和解决类中的bug。时时刻刻把一个类的整体结构考虑在内是很困难的,会经常忽视一些重要的细节。
如果在应用中包含了以下的情况:
- 这个类是UIViewController的子类。
- 数据直接存储在UIViewController中
- UIViews基本什么没做
- Model是一个单纯的数据结构 (dumb data)
- 单元测试什么都没覆盖到
一个优秀的结构所应该有的特点¶
- 通过明确角色来平衡的分配整体的责任。
- 易测性和第一点是相伴的(不必担心的是,当有了一个合适的结构和就会变得很容易)
- 方便使用并且容易维护
设计模式¶
https://refactoring.guru/
一个一个固定的应用场景。抽象,便于复用和维护。
根据场景选择设计模式。
在一定的环境下,用固定套路解决问题。还可以自己去扩充。
业务流中场景符合哪种设计模式就选择哪种设计模式,有利于以后的维护。
设计模式:研究类和类之间的关系。
为类的创建和类的行为进行总结。
设计模式就是把简单的问题复杂化,标准化,软件规整化,维护起来更加的方便。
学习方法:背案例。
模式的应用场景¶
- 创建型模式
用来处理对象的创建过程 共5种
- 结构型模式
用来处理类或者对象的组合 共7种
- 行为型模式
用来对类或对象怎样交互和怎样分配职责进行描述 共11种
设计模式基本原则¶
最终目的:高内聚,低耦合
1、开放封闭原则 (OCP,Open For Extension, Closed For Modification Principle)¶
增加新的功能是要通过增加代码进行的,而不是修改原有代码。
对修改关闭,对扩展开放。
例:银行职员:存款 转账 缴费等等如果一个人都做的话就比较繁忙。但是如果有做存款的职员,有做转账的职员,有做缴费的职员,职员就比较轻松,如果要添加新的功能的话也只需要添加一种职员就可以了,增加一个工种就可以,增加一个类。这样就比较好维护。银行职员基类把银行业务员抽象,定义虚函数。然后具体分工,转帐职员实现转账,缴费职员实现缴费。使用的时候就new各种各样的管理员处理事情。
客户端依赖抽象的业务员进行编程,面向抽象类编程,实现了客户端和具体的银行业务员的解耦合。
高级:定义方法银行职员作为参数,在方法中调用职员做事情。
2、单一职责原则 (SRP,Single Responsibility Principle)¶
类的职责要单一,对外只提供一种功能,而引起类变化的原因都应该只有一个。
通俗地讲就是一个类只做一件事
- CALayer:动画和视图的显示。
- UIView:只负责事件传递、事件响应。
3、依赖倒置原则 (DIP,Dependence Inversion Principle)¶
依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。
框架函数不改变,改变的是实现。
面向抽象类编程而不面向子类编程。高层业务逻辑(框架)不是向底层靠,也不是底层向框架靠,而是向协议层抽象层靠。业务层和实现层的解耦合。
不是框架往第三方产品靠也不是第三方产品往框架靠,而是两个都向中间层靠。企业的信息系统实现可扩展的方法。
案例1:
银行框架和第三方产品之间解耦合就是利用中间的抽象层。例如银行使用加密功能,思科和华为都入选,银行定义一套接口.h
让华为和思科都按照这个接口去实现,银行自动的调用这个抽象接口。
案例2:
组装电脑,不同品牌的硬盘,不同品牌的CPU。第三方的产品。业界已经统一了接口。硬盘类定义虚函数接口,这家的硬盘接口和那家的硬盘的接口都是同一个。实现电脑:抽象的硬盘,抽象的CPU。再使用三星的硬盘,inter的CPU。生产电脑定义一个接口可以使用任何厂家的硬盘任何厂家的CPU。电脑是一个框架,电脑框架和具体的厂商解耦合。
电脑是高层的业务逻辑。低层是具体的厂商产品,高层和低层之间都向中间的协议层靠。进行解耦合。
案例3:
网络框架,自己封装HHNetworking,里面可以调用苹果的网络请求,也可以调用AFNetworking。随意更换。使用者不需要关心。
4、接口隔离原则 (ISP,Interface Segegation Principle)¶
不应该强迫客户的程序依赖他们不需要的接口方法。一个接口应该只提供一种对外功能,不应该把所有操作都封装到一个接口中去。
例如:UITableViewDelegate,UITableViewDataSource
5、里氏替换原则 (LSP, Liskov Substitution Principle)¶
任何抽象类出现的地方都可以用他的实现类(子类)进行替换。实际就是虚拟机制,语言级别实现面向对象功能。
父类可以被子类无缝替换,且原有功能不受任何影响。
例如:KVO
6、优先使用组合而不是继承原则(CARP,Composite/Aggregate Reuse Principle)¶
使用继承,会导致父类的任何变换都可能影响到子类的行为。
使用对象组合,就降低了这种依赖关系。
为类A增加一个方法有几种方法:
-
直接修改类a的代码。
-
代码复用 使用继承。
-
依赖 关联 组合
对类持有 然后增加方法。
创建一个类c,c里面有一个成员变量类a。把a注入到里面,作为构造函数的参数。把一个类注入到另一个类里面。
- Java aop汇编
例:在a类的成员函数前后加一个日志功能,编译之后找到该方法,然后在方法的前后加上需要的功能。
- iOS 消息转发
7、迪米特法则(LOD,Law of Demeter)¶
一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的可维护性。
例如在一个程序中,各个模块之间相互调用时,通常会提供一个统一的接口来实现。这样其他模块不需要了解另外一个模块的内部实现细节,这样当一个模块内部的实现发生改变时,不会影响其他模块的使用。(黑盒原理)
一个类个功能不要设计的太强大的,什么功能都在里面。设计模式就是为了做细了,复杂话。
例:
一个人不要直接和陌生人说话,因为每次换一个陌生人就不认识了,可以通过朋友(中间人)和陌生人说话,陌生人改变了也不影响。
高级:某人可以和某一些陌生人说话,可以把这一类陌生人定义一个抽象陌生人的类,符合这一类的就可以实现说话。继承抽象陌生人的类并且实现指定的接口这样才可以。