关于三者的比较说明,能够看Casa酱的这篇iOS应用架构谈 view层的组织和调用方案,巧神的被误解的 MVC 和被神化的 MVVM篇幅有限,也能够瞅一眼~html
原型模式:使用原型实例指定建立对象的种类,并经过复制这个原型建立新的对象。ios
它是一个很是简单的设计模式,基于“复制”操做。复制指用同一模具生产一系列的产品。模具所基于的物品称为原型。 此模式的最低限度是生成对象的真实副本,以用做同一环境下其余相关事物的基础。设计模式
通俗来讲,若是要建立的新对象和自身差别并不大,其行为略有不一样,且复制自身比手工实例化要好,就可使用原型模式。bash
例如我有一个Person
实例A,我须要一个跟A仅Name
不一样,可是其他属性均相同的新对象B,若是使用者经过新建实例并将A的全部属性赋值给B,这无疑是至关麻烦的,这时咱们就可使用B = [A clone]
来复制A的属性,从而节省大量精力,提升了复用性也便于维护。markdown
最多见的应用就是深复制,如NSMutableArray = [NSArray mutableCopy]
。网络
注:浅复制不属于原型模式,它不知足上面说到的原型模式的最低限度,仅仅是指针拷贝。
复制代码
比较常见的状况就是对自定义对象进行拷贝的时候,咱们须要经过对自定义对象实现NSCopying
协议及其方法- (id)copyWithZone:(NSZone *)zone
。多线程
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。它几乎是全部设计模式中最简单的一个了。架构
最多见的就是[UIApplication sharedApplication]
。mvc
例如一些管理类xxManager
,设置类xxConfiger
等等,都是会频繁使用而且须要共享资源保存临时状态,就可使用单例。 关于多线程下加锁保证只建立一个实例,咱们可使用@synchronized、NSLock等,更推荐使用dispatch_once,性能更优。 甚至咱们还可使用宏来实现单例。框架
因为Objective-C并不能像C++,Java中同样可以隐藏构造函数,小伙伴们仍是能够alloc/init来建立对象,通常有两种解决方案:
工厂方法模式:也叫作虚构造器。定义建立对象的接口,让子类决定实例化哪个类。工厂方法使得一个类的实例化延迟到其子类。
通俗来说,对于有多种相似的产品,咱们能够将产品的公有属性和方法抽象为一个产品基类,将生产产品的工厂抽象为一个工厂基类,并暴露返回产品对象的工厂方法,各自产品的工厂继承自工厂基类,并重载该工厂方法以返回对应的产品对象。
例如一开始的股票详情界面,有指数、沪深、港股、美股等等,分别有一个基于TKHqBaseStockDetailViewController
的详情子类,以及基于TKHqBaseStockDetailFactory
的工厂子类,工厂提供了一个建立详情的方法,使用者可使用对应的工厂子类来获取想要的详情子类。
注:咱们也能够经过传递股票信息在工厂内部经过枚举来直接建立对应的详情子类,而不经过工厂子类来建立,这种就是简单工厂。
复制代码
抽象工厂模式:提供一个建立一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
通俗来说,咱们能够提供一个工厂基类,其中包含了建立一系列产品的工厂方法,而且经过使用预处理或者枚举来生成不一样的工厂子类,这些工厂子类中都实现了基类的工厂方法,并根据本身的需求在创造产品的工厂方法中获取想要的具体的产品子类。
当咱们须要的不只仅是一个产品,而是一个包含了多个相关联或相依存的不一样产品结构的产品族,且咱们不想指定具体的类或者建立的细节。
最多见的就是NSNumber
、NSString
、NSArray
及NSDictionary
。其中NSNumber
中的numberWithBool:
生成的实际类型是NSCFBoolean
类型,而其余的大多数生成的是NSCFNumber
类型,而且都实现了抽象超类NSNumber
的全部定义。这里的NSCFBoolean
和NSCFNumber
就至关于两个工厂子类,超类的全部定义就至关于一系列产品,Fundation框架中抽象工厂的这种特色,被称为类簇。
类簇是Fundation框架中的一种很是常见的设计模式,基于抽象工厂的思想。它将若干个私有具体工厂子类集合到一个公有的抽象超类之下。例如NSNumber
有一系列公有API,定义了各类类型数据的共有行为,咱们在使用时不用关心NSNumber
实例的具体类型。
注:类簇中每每提供了许多生成工厂子类的方法,这些方法不该该在具体的工厂子类中重载,工厂子类只应该关注产品的建立。
复制代码
例如前面说到的股票详情,一旦详情页面的变得复杂,每每须要由多种界面元素来组成,而且随着股票种类的增长,咱们可能并不想要在关注咱们用什么具体的工厂子类去实例化详情,这里咱们就可使用抽象工厂。
能够将详情大体划分为四层:Nav信息层、基础盘口层、图表层和资讯层。定义一个抽象超类详情TKHqStockDetailViewController
,定义一系列基于这四层的公有API,而且声明+ (TKHqStockDetailViewController *)detailWithStock:(TKHqStockModel *)stockModel
的类工厂方法,该方法中经过股票类型建立了不一样的“详情工厂”,最终在各自的工厂子类中实现一系列的API。
适配器模式:将一个类的接口转换成客户但愿的另一个接口。适配器模式使得原来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。
基本上有两种实现适配器的方式:类适配器和对象适配器。
类适配器:经过多继承来实现,在OC中能够经过协议和单继承模拟多继承。协议用于规范统一的接口,父类用于实现具体的新接口,子类经过重载协议的目标接口,在接口内部调用父类的新接口来响应处理。
对象适配器:与类适配器不一样,它不须要继承被适配者,仅仅须要实现统一的协议,并持有一个被适配者的引用,在重载的协议接口中,调用该引用的新接口来响应处理。
两种方式的区别以下:
注:通常来讲,对象适配器适用范围更普遍,对于将来可能新增的须要适配的新接口,也更容易扩展。
复制代码
例如详情的设置页面,咱们发现Cell的结构基本差很少,能够由Title、SubTitle、Detail、AccessoryView四部分组成,其中某些Cell可能显示SubTitle有的不显示;有的显示Detail有的不显示;AccessoryView内容多是个箭头,有的多是个SwitchBar。若是咱们对每种样式去定制化一个Cell,无疑是难以维护和扩展的,这里咱们就能够经过适配器模式,将每种设置的数据适配成规范数据来统一处理。
咱们能够建立一个Protocol来声明目标接口,包括了Title、SubTitle、Detail、AccessoryView四部份内容,而后定义一个Adapter实现该协议,将使用到各类被适配者(在这里也就是不一样设置类型原来使用的Model)持有引用,而后目标接口中判断哪一种引用不为nil,而后根据当前被适配者的接口来获取相应的数据,这样外部在使用不一样设置类型时,只须要将原来的Model传给Adapter,Cell便能经过Adapter来获取统一规范的数据。
注:也能够经过实现Protocol 、集成各自Model的具体子类的类适配器方式来实现上述功能,这样子Adapter中就只处理父类Model的数据,在使用时不一样设置给Cell设置不一样的子Adapter便可。
复制代码
委托模式:主要是适配器模式,它实际上一样是把类的接口变换为客户端要求的另外一种接口,经过Protocol来要求其余类适配它须要的接口,而它自己就是个适配器。
当咱们须要其余类来作一些当前类没法完成的事情,或者须要使用者来处理某些个性化操做。 通常能够经过delegate或者block来实现。
最多见的就是UITableView中delegate和datasource的使用,用来使用者自定义某些设置和响应事件。
例如须要传递上一层数据、须要使用者来定义某些设置、View须要VC来响应push/pop等等。
代理模式:为其余对象提供一种代理以控制对这个对象的访问。其思想是使用一个基本上跟实体对象行为相同的代理。
Objective-C中的delegate属于委托模式,但也基于了代理模式的思想,如第四点所说,也至关于一个智能引用代理,同时经过协议接口的控制,也必定程度上至关于控制了对原对象的访问权限。
NSProxy
桥接模式:将抽象部分与它的实现部分分离,使它们均可以独立地变化。 通俗来说,若是实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,较少耦合。
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新。也叫作发布-订阅模式。
有两种技术都使用了观察者模式:通知和KVO。
中介者模式:用一个对象来封装一系列对象的交互方式。中介者使各对象不须要显示地相互引用,从而使其耦合松散,并且能够独立地改变它们之间的交互。
在多模块的开发中,因为不一样产品模块由不一样小组开发,相互之间的代码相对封闭,可是因为业务关联,每每又须要跟其余模块交互,好比A模块打开B模块页面,B模块又须要查询C模块的数据,通常实现可能直接A调用B模块相关代码,B模块调用C模块相关代码,这样形成的问题一是模块之间相互耦合,独立开发十分困难,须要屏蔽相关代码;二是一旦其余模块的API修改,相关模块全都得改动。
针对这个问题,可使用中介者模式,框架定义了一个中介者基类baseMediator
,并实现了一套协议用于接收外部事件,A模块若是想要与B模块交互,能够经过一个通知方法告诉BMediator
,而后BMediator
根据不一样参数来处理相应事件,这样避免了模块之间的强耦合,同时外部模块也不在关心它的内部实现,只须要关心其暴露出来的事件定义。