《Objective-C编程之道 iOS设计模式解析》笔记

点击获取 《Objective-C编程之道 iOS设计模式解析》Source Code 源码
传送门:点击下载原书 PDF 版本

最近看完了《Objective-C编程之道 iOS设计模式解析》,确实很经典。
书中涉及 21 种设计模式,根据实际应用场景分了 8 个部分:
对象创建、接口适应、对象去耦合、抽象集合、行为扩展、算法封装、性能和对象访问、对象状态。
书中的示例多采用了 OMT 建模技术,所以先了解一下 OMT 基本规范很有必要,另外关于设计模式的基本原则也在此记录一下。

一、关于 OMT

OMT是Object Modeling Technique的缩写, 意为对象建模技术

OMT.png

二、设计模式的基本原则

设计模式的基本原则非常重要,只要真正深入地理解了设计原则,很多设计模式其实就是原则的应用而已,或许在不知不觉中就在使用设计模式了:

  • 单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因。
  • 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。
  • 依赖倒转原则(DIP),A. 高层模块不应该依赖低层模块,两个都应该依赖抽象。B. 抽象不应该依赖细节,细节应该依赖抽象。
  • 里氏代换原则(LSP),子类型必须能够替换掉它们的父类型。
  • 迪米特法则(LoD),如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
  • 合成/聚合复用原则(CARP),尽量使用合成/聚合,尽量不要使用类继承。

三、对象创建相关设计模式

1. Prototype 原型模式

一般在初始化信息不发生变化的情况下,克隆是最好的办法。这既可以隐藏对象创建的细节,又对性能是大大的提升。

定义:使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象。

适用情景:

  • 需要创建的对象应独立于其类型与创建方式。

  • 要实例化的类是运行时决定的。

  • 不想要与产品层次相对应的工厂层次。

  • 不同类的实例间的差异仅是状态的若干组合。因此复制相应数量的原型比手工实例化更加方便。

  • 类不容易创建,比如每个组件可把其他组件作为子节点的组合对象。复制已有的组合对象并对副本进行修改会更加容易。

2. 工厂方法模式

工厂方法也称为虚构造器。它适用于这种情况:一个类无法预期需要生成哪个类的对象,想让其子类来指定所生成的对象。

定义:定义创建对对象的接口,让子类决定实例化哪一个类,工厂方法使得一个类的实例化延迟到子类。

适用情形:

  • 编译时无法准确预期要创建的对象的类。

  • 类想让其子类决定在运行时创建什么

  • 类由若干辅助类为其子类,而你想将返回哪个子类这一信息局部化

3. 抽象工厂
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。 

软件设计黄金法则:变动需要抽象。 比如,如果APP要支持更换皮肤,可以设计成抽象工厂。

抽象工厂与工厂方法比较

抽象工厂与工厂方法比较.png
说明:当现有的抽象工厂需要支持新的产品时,需要向父类添加相应的新工厂方法,这意味着也要修改其子类以支持新产品的新工厂方法。
4. 生成器模式
定义:  将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现。

适用情景:

  • 需要创建涉及各种部件的复杂对象。创建对象的算法应该独立于部件的装配方式。常见例子是构建组合对象。

  • 构建过程需要以不同的方式构建对象。 将做什么 和 怎么做 两个问题分开解决。

生成器与抽象工厂的比较

生成器与抽象工厂的比较.png
5. 单例模式
定义:保证一个类仅有一个实例,并且提供一个访问它的全局访问点。

适用情形:

  • 类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。

  • 这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。

四、接口适应相关设计模式

1. 适配器模式

适配器模式,用于连接两种不同种类的对象,使其毫无问题地协同工作,有时它也称为包装起"wrapper"。 基本上有两种实现适配器的方式:

1.通过集成来适配来适配两个接口,这种称为类适配器,多通过多重继承来实现,但是OBJ-C没有多重继承,可以通过协议来实现。

2.对象适配器。与类适配器不同,对象适配器不继承被适配者,而是组合一个对它的引用。

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

适用情形:

  • 已有的类的接口和需求不匹配。

  • 想要一个可复用的类,该类能够同可能带有不兼容接口的其它类协作。

  • 需要适配一个类的几个不同子类,可是让每一个子类去子类化一个类适配器又不现实。那么可以通过使用对象适配器(也叫委托)来适配其父类的接口。

类适配器与对象适配器的对比

类适配器与对象适配器的对比.png
2. 桥接模式
定义:将抽象部分与它的实现部分分离,使它们都可以独立的变化。 

适用情形:

  • 不想在抽象与其实现之间实现固定的绑定关系。

  • 抽象及其实现都应该可以通过子类化独立进行扩展。

  • 对抽象的实现进行修改不应该影响客户端的代码。

  • 如果每个实现需要额外的子类以细化抽象,择说明有必要把他们分成两个部分。

  • 想在带有不同抽象接口的多个对象之间共享一个实现。

3. 外观模式
定义:为系统中的一组接口提供一个统一的接口,外观定义一个高层接口,让子系统更易于使用。 

适用情形:

  • 子系统正逐渐变得复杂。应用模式的过程中演化出很多类。可以适用外观为这些子系统提供一个比较简单的接口。

  • 可以使用外观对子系统进行分层。每个子系统级别由一个外观作为入口点。让他们通过其外观进行通信,可以简化它们的依赖关系。

五、对象去耦合相关设计模式

1. 中介者模式

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

定义:用一个对象来封装一系列对象的交互方式。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。 

适用情形:

  • 对象间的交互虽然定义明确然而非常复杂,导致一组对象彼此相互依赖而且难以理解。

  • 因为对象引用了许多其他对象并与其通讯,导致对象难以复用。

  • 想要定制一个分布在多个类中的逻辑或行为,又不想由太多子类。

说明:中介者模式以中介者内部的复杂性代替交互的复杂性,因为中介者封装与合并了colleague的各种协作逻辑,
自身可能变得比他们任何一个都要复杂得多,这会让中介者本身变成无所不知的庞然大物,并且难以维护。
2. 观察者模式
定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。  也称作发布——订阅模式。 

适用情形:

  • 有两种抽象类型相互依赖。将他们封装在各自的对象中,就可以对他们单独进行改变和复用。

  • 对一个对象的改变需要同时改变其他对象,但是又不知道有多少对象待改变。

  • 一个对象必须通知其它对象,但是又不知道其他对象是什么。

通知与键值观察直接的主要差别

通知与键值观察直接的主要差别.png

六、抽象集合相关设计模式

1. 组合模式
定义:将对象组合成树形结构以表示“部分——整体”的层次结构,组合使得用户对单个对象和组合对象的使用具有一致性。 

适用情形:

  • 想获得对象抽象的树形表示(部分——整体层次结构)

  • 想让客户端统一处理组合结构中的所有对象。

2. 迭代器模式
定义:提供一种方法访问一个聚合对象中的各个元素,而又不暴露对该对象的内部表示。 

适用情形:

  • 需要访问组合对象的内容,而又不暴露其内部表示。

  • 需要通过多种方式遍历组合对象。

  • 需要提供一个统一的接口,用来遍历各种类型的组合对象。

基本上由两种类型的迭代器:外部迭代器和内部迭代器。外部迭代器让客户端直接操作迭代过程,所以客户端需要知道外部迭代器才能使用。另一种情况是,集合对象在其内部维护并操作一个外部迭代器。提供内部迭代器的典型的集合对象为客户端定义一个接口,或者从底层的集合一次访问一个元素,或者向每个元素发送消息。

内部迭代器与外部迭代器的区别

内部迭代器与外部迭代器的区别.png

七、行为扩展相关设计模式

1. 访问者模式

访问者模式设计两个关键角色(或者说组件):访问者和它访问的元素。元素可以是任何对象,但通常是“部分-整体”结构中的节点。

定义:表示一个作用于某对象结构中的各元素的操作。它让我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 

适用情形:

  • 一个复杂的对象结构包含很多其他对象,他们有不同的接口,但是想对这些对象实施一些依赖于其具体类型的操作。

  • 需要对一个组合结构的对象进行很多不相关的操作,但是不想让这些操作”污染“这些对象的类。可以将相关的操作集中起来,定义在一个访问者类中,并在需要在访问者中定义的操作时使用它。

  • 定义复杂结构的类很少做修改,但是需要经常向其添加新的操作。

2. 装饰模式

标准的装饰模式包括一个抽象的 Component 父类它为其他具体组件(component)声明一些操作。

定义:动态地给一个对象添加一些额外地职责。就扩展功能来说,装饰模式相比生成子类更为灵活。

适用情形:

  • 想要在不影响其他对象的情况下,以动态、透明的方式给单个对象加职责。

  • 想要扩展一个类的行为,却做不到。类定义可能被隐藏,无法进行子类化;或者,对类的每个行为的扩展,为支持每种功能组合,将产生大量的子类。

  • 对类的职责的扩展是可选的。

装饰模式与策略模式的差异

装饰模式与策略模式的差异.png

范畴 Category 与装饰模式

范畴 Category 与装饰模式.png
3. 责任链者模式

责任链模式的主要思想是,对象引用了同一类型的另一个对象,形成一条链。链中的每个对象实现了同样的方法,处理链中第一个对象发起的同一个请求。如果一个对象不知道如何处理请求,它就把请求传给下一个响应器。

定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间发生耦合,此模式将这些对象连成一条链,并沿着这条链传递请求,
直到有一个对象处理它为止。 

适用情形:

  • 有多个对象可以处理请求,而处理程序只有在运行时才能确定。

  • 向一组对象发出请求,而不想显示地指定处理请求的特定处理程序。

八、算法封装相关设计模式

1. 模板方法模式

该模式的基本思想是在抽象类的一个方法中定义“标准”算法。在这个方法中调用的基本操作应由子类重载予以实现。这个方法被称为“模板”,因为方法定义的算法缺少一些特有的操作。

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

适用情形:

  • 需要一次性实现算法的不变部分,并将可变的行为留给子类来实现。

  • 子类的共同行为应该被提取出来放到公共类中,以避免代码重复。现有的代码的差别应该被分离为新的操作,然后用一个调用这些新操作的模板方法来替换这些不同的代码。

  • 需要控制子类的扩展。可以定义一个在特定点调用“钩子”(hook)操作的模板方法,子类可以通过对钩子操作的实现在这些点扩展功能。

模板方法会调用5种类型的操作:

  • 对具体类或客户端类的具体操作

  • 对抽象类的具体操作

  • 抽象操作

  • 工厂方法

  • 钩子操作

模板方法与委托模式的比较

模板方法与委托模式的比较.png
2. 策略模式
定义:定义一系列算法,把他们一个个封装起来,并且使他们可相互替换。本模式使得算法可独立于使用它的客户而变化。 

适用情形:

  • 一个类在其操作中适用多个条件语句来定义很多行为。我们可以把相关的条件分支移动到他们自己的策略类中。

  • 需要算法的各种变体。

  • 需要避免把复杂的、与算法相关的数据结构暴露给客户端。

提示:如果代码中有很多条件语句,就可能意味着需要把它们重构成各种策略对象。
3. 命令模式
定义:将请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。 

适用情形:

  • 想让应用程序支持撤销与恢复。

  • 想用对象参数化一个动作以执行操作,并用不同命令对象来代替回调函数。

  • 想要在不同时刻对请求进行指定、排列和执行。

  • 想记录修改日志,这样在系统故障时,这些修改可在后来重做一遍。

  • 想让系统支持事务,事务封装了对数据的一系列修改。事务可以建模为命令对象。

九、性能和对象访问相关设计模式

1. Flyweight pattern 享元模式

实现享元模式需要两个关机组件,通常是可共享的享元对象和保存它们的池。

定义:运用共享技术邮箱的支持大量细粒度的对象。

适用场景:

  • 应用程序使用很多对象

  • 在内存中保存对象会影响性能

  • 对象的多数特有状态(外在状态)可以放到外部而轻量化

  • 移除了外在状态后,可以用较少的共享对象替代原来那组对象

  • 应用程序不依赖对象标识 节省内存

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

适用情形:

  • 需要一个远程代理,为位于不同地址空间或者网络中的对象提供本地代表。

  • 需要一个虚拟代理,来根据要求创建重型的对象。

  • 需要一个保护代理,来根据不同访问权限控制对原对象的访问。

  • 需要一个智能引用代理,通过对实体对象的引用进行引用技术来管理内存。也能用于锁定实体对象,让其他对象不能改变

十、对象状态相关设计模式

1. 备忘录模式
定义:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。 

适用情形:

  • 需要保存一个对象(或某部分)在某一时刻的状态,这样以后就可以恢复到先前的状态。

  • 用于捕获状态的接口会暴露实现的细节,需要将其隐藏起来。

参考链接1

参考链接2

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,036评论 1 32
  • 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设...
    于先笙阅读 443评论 1 3
  • 创建型模式 工厂模式 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设...
    隔墙送来秋千影阅读 2,603评论 0 11
  • 01 稍微一亲近就口无遮拦的毛病必须改。 02 多把“你听懂了没”换成“我讲明白了没”。 03 别人给你发消息一定...
    了悟空空阅读 477评论 0 0
  • 这周过得好快,而且还放了3天的假期。这周的冬季三项可以说十分紧张又精彩,跳长绳的时候同学们都特别努力,最终也取得了...
    机械181尤阅读 243评论 0 0