ios设计模式

这次我们要遵循两个基本原则:
找出 #变化 封装之
优先使用对象聚集,而不是继承

1.适配器

用于连接两种不同的东西,也称包装器。概念简单,就是我们常说的“加一层封装”,下面是它的类图:


Paste_Image.png

在OC中,可以使用协议的模式,让实际的适配器遵循某些方法,对于具体的实现我们不用知道,我们可以通过调用适配器的方法直接得到结果。
实际使用中,和OC习惯的回调不大一样,这里会像java一样把protocol当做接口使用。使用的是实现该protocol的实例,直接调用protocol中定义的方法。

2.桥接模式

把抽象层次结构从实现抽离出来,使之独立变更。先看类图:

桥接模式类图

Abstraction接口中持有具体实现接口Implementor的实例,前者的operation实际调用的是实例对象的operationImp方法。注意:Abstraction可以和Implementor完全不同,比如前者是复杂操作,后者实现的是基本操作。

在以下情形,自然会想到使用这一模式:

  • 不想在抽象于其实现之间形成固定的绑定关系(这样就能在运行时切换实现);
  • 抽象及实现都应可以通过子类化独立进行拓展;
  • 对抽象的实现进行修改不应该影响客户端代码;
  • 如果每个实现都需要额外的子类以细化抽象,则说明有必要把他们分成两个部分;
  • 想在带有不同抽象接口的多个对象之间共享一个实现。

看了两个例子,榴莲书上的游戏控制器&仿真器,和图形&绘图程序(下面有链接)的例子,这个模式应对的是类爆炸的问题,N*N的应对策略,就是两者都会独立拓展的情况。当一个模型有多个维度特性且需要拓展的时候,最好不要使用多继承(实现多个接口)。这样在后期拓展中很可能加一种类型,就会多出其他维度N-1个类,正如下面引用所说的一样。其实在日常使用中,我们已经经常使用这种模式,比如创建三种大小的毛笔,同时每种毛笔有五种颜色,这时我们肯定不会新建15个毛笔类,会将颜色聚合到毛笔当中作为属性。这个的难点在于我们往往不能很清楚的将多种属性分离,让他们独立开。

引用 : http://www.cnblogs.com/rush/archive/2011/06/29/2093743.html

当一种抽象类型可能有多种实现方式时,一般情况我们可以考虑使用继承来解决抽象类型的多种实现,在抽象类型中定义接口,而子类负责接口的具体实现。但这种做法缺乏灵活性,由于抽象类型和子类之间紧紧地绑定在一起,使得这种关系在运行时不能再修改,这使得它难以修改、扩展和重用不利于抽象和实现解耦,而且这也违背OOP原则:“优先使用对象聚集,而不是继承”。
结合例子再看概念,就发现绘图程序就是这里图形的具体实现。图形和绘图程序会同时拓展的。

3.工厂

简单工厂、工厂方法模式、抽象工厂
简单工厂——传入产品类型,将你想要的产品构造出来。通常内部有大的switch来判断,也常常会构造成一个单例。不易拓展产品种类。
工厂方法模式——一般的工厂模式,会有一个工厂和产品的接口,可以方便的增加产品种类,也很方便的动态在运行时决定使用哪种类型的产品,利用反射。


工厂方法模式

抽象工厂——用来生产不同产品族的全部产品,其中产品种类是不能改变的,因为改变它需要修改所有的工厂实现子类。但是定义哪个为产品种类,哪个为产品族可依据实际情况去选择。比如下图中,保证三个控件是不变的,变化的始终是风格类型。


抽象工厂模式

4.生成器模式

用于大量构建相似的复杂对象,尤其是内部组件装配顺序不同,就会有差异的产品。此外对于多部件创建复杂(需要封装的)的产品也可以采用这个模式。
||或者具有多种固定属性(力量、敏捷、智力)同时还有由固定属性决定的表现属性(攻击、防御)的,或者拥有两种特质的比如怪物同时有普通怪、boss怪,同时他们都还有类别之分巨人、弓手等。||
下面的类图可以清晰的看到,Director将Builder的装配步骤和client隔离开。Builder的每一个builderPart返回的可以是对象本身,这样可以形成链式调用,在java中写十分爽,在OC中没什么卵用。


Paste_Image.png

5.外观模式

显而易见,这是一个访问子系统的manager,我们经常使用这个,就是常说的统一入口或加一层封装(=。=)。但是需要注意的是,这个对于子系统的内部实现方式的修改是很方便的,但是一旦要增加新的外部接口,可能会要求修改外观类,违反开闭原则。所以我认为它是不适应子系统接口变化的,只适用于子系统实现变化。


Paste_Image.png

6.组合模式

组合模式使用场景:

  • 想获得对象抽象的树形结构(装饰器模式运用了组合模式)
  • 想让客户端统一处理组合结构中的所有对象(比如遍历)
直观的运行时结构图

很明显,当一个图画由折线和点构成,我们可以使用树形链式结构保存它。
对于组合模式,有两个品种:

透明方式:
在Component中声明所有用来管理子对象的方法,如Add()方法,Remove()方法及GetChild()方法,所有实现Component接口的子类都具备这些方法,这使得Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。

大家可以回忆一下代理模式(Proxy)中,Proxy,RealSubject类和Subject接口具备一致的行为接口,从而使得被代理者对于客户端是透明的。
正由于我们的Composite和Leaf都具备一致的接口行为,但我们知道Leaf不应该具有Add(),Remove()及GetChild()方法,因为我们叶子节点不能再添加和移除节点了。

安全模式:
在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。

通常组合结构的内部表示不应暴露给客户端,因此组合模式总是和迭代器模式一起使用,以遍历组合对象的每一个项目。


插播一些OC接口的使用

*在接口中,我们可以声明属性。其实可以认为定义了一套get/set方法,但是没有实现的。如果这个接口的实现要使用它,需要在.m中来一个@synthesize。同时如果不需要使用到这个属性,最好来个@dynamic来忽略它(增强可读性)。
*重新声明在子类中重载的属性和方法是好习惯。

7.迭代器

迭代器提供了一种顺序访问聚合对象中元素的方法,而无需暴露结构的底层表示和细节。榴莲书 中描述了外部和内部迭代器区分是在客户端维护迭代器还是在集合对象内部维护,我认为最好是在外部维护,降低耦合性还可以独立变化。

外部迭代器 内部迭代器
客户端需要知道外部迭代器才能使用,但提供了更多的控制 客户端无需知道任何外部迭代器,通过集合对象的特殊接口,一次访问一个元素或向全体发消息
客户端创建和维护外部迭代器 集合对象本身创建并维护外部迭代器
客户端可以使用不同外部迭代器实现多种类型的遍历 客户端可以在不修改客户端代码的情况下,选择不同的外部迭代器

看了书中给的内部迭代器的例子,可以传入一个block来对每一个节点操作,控制遍历的进行&终止等,不影响拓展。所以内部维护的迭代器也很好用,OC中常用集合对象都有内部迭代器。但java中多是取得iterator,自己while遍历的。

8.访问者

访问者模式分为两个角色,访问者和它访问的元素。元素可以是任何对象,但通常是“部分-整体”结构中的节点,见组合模式(容器性质)。访问者知道复杂结构中每个元素,可以访问每个元素的节点,并根据元素的特征、属性或操作执行任何操作。
注意
复杂结构可以包含很多其他对象,而且它们有不同的接口,对这些对象实施一些依赖于其具体类型的操作
需要对一个组合结构中的对象进行很多不相干的操作,但是不想让这些操作“污染”这些对象的类。将操作集中起来,放在访问者当中
复杂结构很少修改,但是经常定义新的操作

一个想法,很多时候网络数据流是不会变的(网络请求-增加-提交),但是会有很多业务类型会读取(访问)这个数据流,将其结果写到操作数据流当中去,是不是意味着我们可以将业务类型开放在一个访问者当中,不影响主流程。
比如订票的流程,整体大的框架是不变的(填写乘机人-填写联系人-填写邮寄地址-点击生单),但是会有很多新增的儿童购买成人票加入进来。
常见场景,发现新增操作会污染类,我们会选择将这个方法封装一下,使用一个XXXHandler去做这个事情,这时候XXXHandler就是访问者,同时XXXHandler不应该作为成员变量持有,而是作为一个方法的参数传入,再度解耦,这一步是比较容易忽视的一点。

类图

9.装饰

当我们想要不影响其他对象,用动态、透明的方式为一个对象添加职责(不增加他对外暴露的方法)的时候,我们可以使用这个方法。观察类图,这里使用了类似builder的方法,每次处理完之后还是自己,可以动态配置,透明调用。在OC中,分类可以替代这个Decorator的继承,这个方法被榴莲书叫做范畴。它实现少量的装饰器的时候,比真正的子类方式更为轻量、更为容易。

类图

10.责任链

使用场景:

有多个对象可以处理请求,而处理程序只有在运行时才能确定
向一组对象发出请求,而不想显示的指定处理请求的特定处理程序

类图

对对象进行一系列的处理操作,是一种顺延式的处理。这个节点处理不了,就往下传递。

11.模板方法

抽象出共同的部分——模板方法(比如:把大象关冰箱里 打开冰箱门—把大象塞进去—关上冰箱门调用的顺序),然后在子类中实现或重写三个步骤方法的具体内容。一般模板方法只定义了调用顺序,是不可以修改的,必要时也可以重写模板方法。模板方法是父类调用子类的操作方法,形成一个控制结构流程倒转。

类图

在iOS开发当中,ViewController的生命周期函数就是模板方法,我们重写了生命周期的各个函数,然后有一个不可见的模板方法按顺序调用了这些生命周期函数。

使用场景
需要一次性实现算法的不可变部分,并将可变的行为留给子类来实现
子类的共同行为应该被提取出来放到公共类中,避免代码重复。
需要控制子类的拓展。可以定义一个在特定点调用“钩子”操作的模板方法。子类可以通过对钩子操作的实现在这些点拓展功能。(钩子方法就是在某些操作步骤间预留的操作,可以调用以供拓展使用,一般为空。钩子在这里应该是作弊的代名词)

注意 : 可以是用抛出异常的方式,强制子类重写父类定义的步骤方法(打开冰箱门等)。其中钩子方法不必这么做,其实生命周期中的很多方法都是钩子方法,比如drawRectshouldAutorotateToInterfaceOrientation 等本身都是空方法。

12.

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

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,929评论 1 15
  • 小白程序员只能看懂源代码,而大神程序员能看懂文档。 设计模式:为解决特定场景的问题而定制的解决方案。设计原则:构建...
    印林泉阅读 859评论 0 8
  • Design Pattern 设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。设计模式...
    卖萌的二师兄阅读 552评论 0 3
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • 在爱情中,遇人不淑最可怕的后果是 它让你变成更差的自己 今天我想和大家讨论一个生活在镁光灯下的明星 ▼ 贾静雯 她...
    结果儿阅读 801评论 0 1