设计模式 设计原则 7大原则 模式: 23 种模式: 创建型模式, 结构型模式, 行为型模式 设计原则 说明 : 为了代码可重用性、让代码更容易被他人理解、保证代码可靠性等等, 设计模式 首先要满足以下7点设计原则 单一职责原则 一个类只承担一个职责, 尽量不要身兼数职(功能) 开闭原则 开 : 类、模块、函数,可以去扩展(增加方法和属性), 闭 : 但原有方法尽量不直接修改,尽量用继承或组合的方式来扩展类的功能 里氏替换原则 子类可以直接替换父类,而不用做适配(子类可以扩展父类的方法,但不应该复写 父类的方法 ) 接口隔离原则 对象不应被强迫依赖它不使用的方法(不要把所有功能都集中到一个接口里) 强迫所有动物都有飞 的功能就是不合理的, 应根据动物种类不同设计相符的接口 依赖倒置原则 高层模块不应该直接依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细 节;细节应该依赖抽象 加载图片直接使用sd_webImage方法,一旦换框架或者方法名改变, 高层需要大量 修改(依赖低层) 在它们之间建抽象层返回xx_webImage方法, 让抽象层其调用具体实现方法 迪米特法则 一个对象应该对其他对象保持最少的了解,实现低耦合、高内聚 视频播放关系播放方法即可, 不要去关心视频卡顿, 如何渲染等, 让别人自己处理 组合/聚合复用原则 少用继承,多用合成关系来拥有已存在的功能 一个模块不要通过继承另一个模块方式来扩展功能,一个模块一旦修改, 它的继承 者也必须修改, 耦合太强, 无法复用 人可以是老师,学生,校长, 继承只能选一种, 无法满足即是校长又是老师的多重身 份, 可以赋予一个角色对象, 让角色去配置相应的职责 创建型模式 说明: 使用合适的方式创建对象 不同需求使用不同的创建方式 抽象工厂模式 通过一个类的不同接口,直接返回不同的子对象, 无需知道如何创建的 苹果工厂同时生产苹果鼠标和苹果键盘, 想要苹果鼠标 : 苹果工厂.创建苹果鼠标 (); 即可 缺点 : 需要一个对象就必须把其工厂一起继承过来 想要苹果鼠标 必须继承 苹果工厂 Class A 有多个创建initWith_XX 方法,选择适合的一个 必须继承这个类才能使用这个初始化反方,同时也把不需要的创建功能继承过来 建造者模式 通过创建多个不同子对象, 来组合成一个复杂的对象(而不是直接创建, 存在多种 不同的组合情况) 优点: 1、建造者独立,易扩展。 2、便于控制细节风险。 缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的 建造类。 比如套餐A: (汉堡+薯条+可乐) , 套餐B: (汉堡+鸡翅) 等等不同组合 比如 链式语法应用 C = A.B.D 。不过随着功能越复杂,类内部代码逻辑也越复 杂,维护性下降。 工厂方法模式 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使 其创建过程延迟到子类进行 汽车工厂有不同接口使得生产出不同配置的汽车, 比如红色,蓝色, 或者有天窗和 无天窗的 生产汽车是汽车工厂类, 生产飞机是飞机工厂类, 不是在一个类里 比如类方法 [NSString stringWithFormat: ],子类在初始化时调用 原型模式 通过拷贝这些原型创建新的对象 通过复制的方式创建一个对象(区别深复制和浅复制) 对象Copy,比如copy协议设计 单例模式 一个类仅有一个实例,并提供一个访问它的全局访问点 , 只能被实例化一次(iOS 中dispatch_once修饰) , 全局访问, 运行过程不销毁, (适应一个全局使用的类频 繁地创建与销毁时, 节省系统资源) 全局共享一个对象,比如GCD 的 dispatch_once 使用 结构型模式 适配器模式 将一个类的接口(无法直接使用,不兼容)转换成客户能直接用的另外一个接口(兼容 的) 不同类型的内存卡都不能直接插在电脑端口上使用, 但是中间接上读卡器(适配器) 就可以了 就是通过接口兼容适配,格式转换等产生新的可使用的接口 使用一个类方法时,不能直接拿来使用,需要一层转化: 比如swift 使用OC 方 法内部会进行方法名和参数的适配 桥接模式 当对象是由多个维度不断变化组合产生时, 如果直接继承就会导致子类种数爆炸 (三维排列组合 : n*m*k) 比如画一个有颜色的形状(二维:颜色+形状), 不同形状和颜色组合和种类繁多, 那 么桥接如何使用 ? 形状和颜色由单独的类(Color 和 Shape)去完成, 而对象能够接受这两个类对象 (红色:Color.red , 圆形: Shape.circle(...)): 1.需求画一个红色的长方形(宽20,高30) obj.setColor(Color.red); obj.draw(Shape.rectangle(w:20,h:30)); 2.需求画一个蓝色的圆形(半径30,x) obj.setColor(Color.blue); obj.draw(Shape.circle(r: 10, x: 100, y: 100)); 组合模式 树形结构 : 就是在一个对象中包含其他对象,这些被包含的对象可能是终点对象 (不再包含别的对象),也有可能是非终点对象(其内部还包含其他对象,或叫 组对象),我们将对象比作节点 , 那么整体结构就是树形结构了 所以组合模式的使用场景就是出现树形结构的地方。比如:文件目录显示,多及 目录呈现等树形结构数据的操作 装饰器模式 在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能 iOS使用 Category 分类添加方法本身就是一种装饰器模式 王者荣耀等类Dota游戏中,英雄升级一样。每次英雄升级都会附加一个额外技能 点学习技能, 那么只要对技能类动态添加或者删除方法(技能) , 英雄类(hero)直接 使用新方法(技能)即可 Category 分类方法等应用 外观模式 黄牛模式 : 完成一个类功能需要经历多个步骤(方法)才能完成时, 如果有一个抽象 类(代理人)来完成这些步骤, 就好了(把任务交给代理人去完成复杂的流程, 让代理 人去关联相关类), 懒得麻烦 , (比如代上牌) 对外暴露方法(启动电脑,关闭电脑)。 启动电脑(按一下电源键):启动CPU、启动内存、启动硬盘 关闭电脑(按一下电源键):关闭硬盘、关闭内存、关闭CPU 视频播放器设计时,对外暴露 play,stop等方法,减少过多设置操作 享元模式 租赁(共享)模式 : 在有大量对象时,有可能会造成内存溢出,我们把其中共同的 部分抽象出来,如果有相同的业务请求,直接返回在内存(比如内存, 线程池, 栈 等中寻找)中已有的对象,避免重新创建 比如共享单车, 不需要每次需要单车都去购买一辆, 直接租赁一辆即可(发现共享 单车(已创建的对象), 并且闲置就可以使用, 自行车库就好比内存,线程池,栈等) 比如UITableViewCell ,UIColloectionViewCell 等复用,从内存中找位使用大 对象 缺点:一些状态没有被重置,注意 代理模式 专业(授权)机构模式 : 一些任务很难或者没有权限直接去处理时,就需要一个代理 机构去(专业, 有授权等等)完成, 帮自己解决问题(比如第三方认证机构) 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化 (Synchronization)代理。 8、智能引用(Smart Reference)代理 iOS 中大量使用代理 delegate,UITableView等等 行为型模式 职责链模式 或责任链 场景1: 不知道接收者是谁, 将请求交给能处理的处理机构, 让机构去分配责任人处 理, 并给到接收者 避免请求发送者与接收者耦合在一起 : [请求发送者A -> 请求处理者(责任人)B (接单人B1 -接单人B2 - 接单人B3 ...) -> 接收者C ] , 接单人形成一条链, B1不 能处理就询问B2,再询问B3...直到谁能处理就处理. 优点 : 1. 请求者和接收者解耦, 2.请求者不需要知道处理者是怎么处理的, 只管发 送 3. 处理链可独立扩展,增删处理逻辑 缺点 : 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行 代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特 征,有碍于除错。 比如你请假,申请之后,到了组长那,小于3天直接批了,但是超过3天的,就继 续向上申报主管审批,这样根据不同情况不同处理。假如你请假两年,也可能申 请失败(处理失败) 【比如发送一个请求,】 【 请求模块根据不同参数去不同服务器,然后可能拿到数据,也可能返回错 误,】 【这个时候需要把数据 继续给 数据系列化模块处理,解析数据,】 【然后再给数据转换模块处理,转换成对应的model ,】 【最后才返回给请求着。】(中间不同模块对应各自责任) 命令模式 根据命令操作 : 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关 系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种 无法抵御变化的紧耦合的设计就不太合适,比如事务处理(命令), git操作 Stock abcStock = new Stock(); BuyStock buyStockOrder = new BuyStock(abcStock); SellStock sellStockOrder = new SellStock(abcStock); Broker broker = new Broker(); broker.takeOrder(buyStockOrder);//根据传入命令处理 broker.takeOrder(sellStockOrder);//根据传入命令处理 broker.placeOrders(); 解释器模式 这种模式实现了一个表达式接口,该接口解释一个特定的上下文。传入一个对象, 返回其解释或者算法结果,或者编译结果 编译器、运算表达式计算, 树形型结果递归算法 等等 迭代器模式 遍历一个聚合对象 : 提供一种方法顺序访问一个聚合对象中各个元素, 而又无须 暴露该对象的内部表示。 把在元素之间游走的责任交给迭代器,而不是聚合对象, 比如链表hasNext, next 中介者模式 多个对象之间都通过中介者来处理事务, 对象之间解耦 优点: 相互解耦, 独立升级 缺点 : 中介者会变得膨胀 备忘录模式 临时存储,备份, 方便撤销或者回滚等等 编辑过程存储部分编辑内容临时信息, 可以进行撤销等操作, 操作事务同样支持 回滚等 观察者模式 通知功能 : 一对多依赖关系, 一个对象发生改变, 其他依赖立马收到通知 iOS的通知, KVO 等等 状态模式 状态切换 : 类的行为是基于它的状态改变的 , 扩展时遵循开闭原则 , 且状态的切 换必须在运行过程中 // 初始为开始状态 context = context.setState(new StartState()); // 切换为关闭状态 context.close(); // 切换为开始状态 context.start(); 策略模式 解决问题的多样性 : 封装很多方法类, 在运行过程中可以选择不同的方式继续解 决问题 , 它们可相互替换 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略 模板方法模式 父类已经定义好了主要的操作流程和规则, 由其子类进行实现, 可以根据自身需求 在主题架构上进行细节多样化 商品房一栋楼的架构上下层都是一样的, 但是装修可以自己定义(建筑结构不能改, 装饰可以改) iOS 很多UIKit 类 访问者模式 对类增加 与 架构和其他固定结构都无关的一些功能, 我们增加一个访问类, 专门 封装这些事务 房屋的骨架和装修已经固定, 但是 来房间的打扫阿姨, 或者 客人都是访问者, 将他 们与房屋(类)本身区分开 对非主体结构逻辑之外的细节,封装处理,方便访问,库也方便迭代 其他 软编码: 耦合度比较低 硬编码: 耦合度比较高