iOS常用设计模式综述

1-设计模式主要有三种:

  • 创建型模式:主要用于描述如何创建对象;
  • 结构型模式:主要用于描述如何实现类或对象的而组合;
  • 行为型模式:主要用于描述类或对象怎样交互以及怎样分配职责;

2-面向对象设计原则

  • 单一职责原则:一个类只负责一个功能领域中的相应职责;
  • 开闭原则:软件实体应对扩展开发,而对修改关闭;抽象化是开闭原则的关键;
开闭1.png

开闭2.png
  • 里氏代换原则:所有引用基类对象的地方能够透明地使用其子类的对象;

  • 依赖倒转原则:抽象不应该依耐于细节,细节应该依耐于抽象; 即针对接口编程而非针对实现编程;在实现依耐倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入的方式注入其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象.常用的注入方式有:构造注入/设值注入/接口注入;

    开闭原则是目标-里氏转换是基础-依赖倒转是手段;

  • 接口隔离原则:使用多个专门的接口,而不是使用单一的总接口;

  • 合成复用原则:尽量使用对象组合,而不是继承来达到复用的目的; "Has-A":用组合;"Is-A":用继承;

  • 迪米特法则:一个软件实体应当尽可能少的与其他实体发生相互作用;

3-创建对象与使用对象-谈谈工厂的作用

  1. 对象相关职责:对象本身所具有的职责/创建对象的职责/使用对象的职责;
  2. 创建对象的方式:
  • 使用new关键字直接创建;
  • 使用反射机制创建对象;
  • 通过工厂类创建对象;

创建型模式

1- 简单工厂模式

简单工厂1.png
简单工厂2.png

优点:

  • 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅'消费'产品,简单工厂模式实现了对象创建和使用的分离;
  • 通过参数设置,可以减少使用者的记忆量;

缺点:

  • 简单工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响;
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护;
  • 使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构;

2- 工厂方法模式

简单工厂存在严重的问题:当系统中需要引入一个新产品时,由于静态工厂方法通过传入参数的不同创建不同的产品,这必定 要修改工厂的源代码.违背"开闭原则";

工厂方法1.png

工厂方法2.png

组成:

  • Product(抽象产品)--(UIView)
  • ConcreteProduct(具体产品)--UIButton/UIView/UITableView
  • Factory(抽象工厂)
  • ConcreteFactory(具体工厂) -- ButtonFactory/TableViewFactory

提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象;即为每一个工厂方法独立出一个类;

优点:

  • 弥补了简单工厂的缺点:新增产品的时候只需要新增一个具体工厂和具体产品即可;增强系统扩展性;

缺点:

  • 新增产品的时候通过增加具体产品类和具体工厂,系统类个数成对增加,增加了系统复杂度;
  • 增加系统抽象性和理解难度;(可以理解)

3-抽象工厂模式

对工厂方法进一步补充:将一些相关的产品组成一个"产品族",由同一个工厂来统一生产;

产品族 .png

抽象工厂和工厂方法模式的区别:工厂方法模式针对的是一个产品等级结构;而抽象工厂需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建;

抽象工厂1.png

抽象工厂2.png

优点:

  • 增加新的产品族很方便;比如增加一套WinterSkinFactory;

缺点:

  • 增加新的产品等级结构麻烦;比如增加一张图片显示的时候;

4-单例模式

结构型模式

1-适配器模式 (AdapterPattern)

组成:

  • Target(目标抽象类):
  • Adapter(适配器类): 对Adaptee和Target进行适配;
  • Adaptee(适配者类): 被适配的角色,定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码;
适配器1.png

2-桥接模式 Bridge

如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来使两者可以独立扩展,将抽象部分和它的实现部分分离,使他们都可以独立的变化;

  • Abstraction(抽象类):
  • RefinedAbstraction(扩充抽象类):
  • Implementor(实现类接口):
  • ConcreteImplementor(具体实现类):

[图片上传失败...(image-1b7b7f-1520597346134)]

- (void)viewDidLoad {
    [super viewDidLoad];
     //
    MessageImplementor *impl = [MessageSMS new];
    AbstractMessage *message = [[CommonMessage alloc] initWithImplementor:impl];
    [message sendMessag:@"加班申请速批" toUser:@"李总"];
    
    //
    impl = [MessageEmail new];
    message = [[UrgencyMessage alloc] initWithImplementor:impl];
    [message sendMessag:@"加班申请速批" toUser:@"李总"];
}

AbstractMessage:

- (void)sendMessag:(NSString *)message toUser:(NSString *)user
{
    [self.impl send:message toUser:user];
}    

3-装饰模式 Decotator

如果是创建UI的时候,将公共部分抽离,不同的部分使用装饰模式装饰后使用;

当不能采用生成子类的方法进行扩充时.一种情况是:可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长.另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类;

优点:比静态继承更加灵活 与对象的静态继承相比,decorator模式提供了更加灵活的向对象添加职责的方式,可以用添加和分离方法,用装饰在运行时刻增加和删除职责,相比之下,继承机制要求为每个添加的职责创建一个新的子类(例如BorderScrollable,TextView,BorderTextView),这会产生许多新的类,并且增加系统的复杂度;此外,为一个特定的component类提供多个不同的decorator类,这就使得你可以对一些职责进行混合和匹配;

组成:

  • Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

  • ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

  • Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。

  • ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

装饰1.png

透明装饰模式: 在透明装饰模式中,要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型;

Component component,componentSB,componentBB; //全部使用抽象构件定义
component = new Window();
componentSB = new ScrollBarDecorator(component);
componentBB = new BlackBorderDecorator(componentSB);
componentBB.display();      

半透明装饰模式:透明装饰模式的设计难度较大,而且有时我们需要单独调用新增的业务方法。为了能够调用到新增方法,我们不得不用具体装饰类型来定义装饰之后的对象,而具体构件类型还是可以使用抽象构件类型来定义,这种装饰模式即为半透明装饰模式,也就是说,对于客户端而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这是不透明的。

Document  doc; //使用抽象构件类型定义
doc = new PurchaseRequest();
Approver newDoc; //使用具体装饰类型定义
newDoc = new Approver(doc);  

4- 外观模式 Facade

外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。
eg:

外观1.png

外观模式通过引入一个新的外观类(Facade)来实现该功能,外观类充当了软件系统中的'服务员',它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互.那些需要交互的业务被称为子系统;如果没有外观类,那么每个客户类需要和多个子系统之间进行复杂的交互,系统的耦合度将很大;而引入外观类之后,客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度.

将分散的多个子系统接口调用集中到外观类的接口(比如弹框的封装也可以说是用了外观模式:把创建/显示集成到一个接口show中).

5-代理模式

行为型模式

1-观察者模式

定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新.

2-策略模式 strategy

在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略;
策略模式目的:将算法的定义和使用分开,也就是将算法的行为和环境分开;
[图片上传失败...(image-44220d-1520597346134)]
策略模式结构:

  • Context(环境类):是使用算法的角色,在解决某个问题时,可以采用多种策略.在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略;
  • Strategy(抽象策略类):为所支持的算法声明了抽象方法,是所有策略类的父类;环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的方法;
  • ConcreteStrategy(具体策略类):实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理;
StudentDiscount *discount = [StudentDiscount new];
MovieTicket *ticket = [MovieTicket new];
ticket.price = 200.0;
ticket.discount = discount;
NSLog(@"%f",ticket.price);



@implementation MovieTicket
- (double)price
{
    return [self.discount calculate:_price];
}
@end

3- 状态模式

state(状态模式):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类;

  • 环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
  • 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
  • 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

此模式和策略模式类似,策略模式封装的是算法,而这个封装的是状态;

参考

史上最全设计模式导学目录(完整版)
可复用面向对象软件的基础

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