在iOS中理解设计模式

设计模式即编码的工程化,是代码设计经验的总结。使用设计模式可提高代码的复用性、可读性和可靠性。设计模式在各类面向对象的语言中基本相通,仅在具体的实现语法上略有差异,下面我们以OC为例来理解和研究一些常用的设计模式。


单例模式

保证程序运行中,一个类全局只有一个实例。它提供了对类对象的全局访问点,在整个过程中共享着一份资源。

应用:登录控制体系、网络请求、音乐播放、分享体系等。

+ (instancetype)sharedInstance {

      static Singleton *singleton = nil;

      static dispatch_once_t onceToken;

      dispatch_once(&onceToken, ^{

            singleton = [[Singleton alloc] init];

      });

      return singleton; 

}

//严谨情况下应把copyWithZone和mutableCopyWithZone也重写

注:可将allocWithZone重写为dispatch_once实现单例,sharedInstance中调用默认的alloc init(alloc会默认调用allocWithZone),此时,单例可被继承,重写init方法实现子单例的扩展。如下:

static Singleton *_instance;

+ (id)allocWithZone:(struct _NSZone *)zone {

      static dispatch_once_t onceToken;

      dispatch_once(&onceToken, ^{

            _instance = [super allocWithZone:zone];

      )};

      return _instance;

}

+ (instancetype)sharedInstance {

       if(!_instance) {

             _instance = [[Singleton alloc] init];

        }

        return _instance;

}

使用带参数的宏定义可以把单例模式的声明优化到只写一次,在各单例类中的.h、.m中只需调用宏定义即可。

最后补充一下iOS系统的单例类:UIApplication,UIScreen,NSNotificationCenter,NSFileManager,NSUserDefaults,NSURLCache,NSHTTPCookieStorage等。

工厂模式

简单工厂模式

一个工厂类,根据传入参数不同,决定初始化某个具体产品实例。

应用理解:一个简单四则运算计算器。如果不使用工厂模式,要实现加减乘除四个方法就需要new4个运算方法类,这显然不是一个完美的解决方案。此时,若有个产品基类BaseCalculate,它包括加减乘除四个产品类(Add,Minus,Multiply,Devide),在需要实例化运算对象的地方,使用运算工厂类CalcuteFactory,根据类型返回产品类的方法-(BaseCaculate *)createWithType:(id)type;生成对应运算的产品类对象。

简单工厂模式

缺点:增加或者修改产品类时,需在代码层次修改工厂类(此时需重新测试工厂类),不够灵活,不便扩展。

为解决上述缺点,出现了第二种工厂模式:

工厂方法模式

一个工厂类,一个产品类对应一个工厂子类(产品与工厂配套),即,扩展产品类别时需同时扩展工厂子类,与简单工厂模式相比,抽象了工厂类。工厂子类中重写抽象工厂类中的方法生产对应的产品子类。

工厂方法模式

缺点显而易见:大量的产品+工厂类,且产品和工厂间隔断严重无法复用相同代码。

于是抽象工厂模式应运而生:

抽象工厂模式

抽象工厂模式的最大特点就是有多个抽象产品类。找出某类产品的共性,设计出此类产品的抽象类(派生出多个具体产品类)。而其具有一个抽象工厂类和多个具体工厂类,每个具体工厂类都可创建多个具体产品类。

抽象工厂模式

观察者模式

发布(publish)- 订阅(Subscribe)模式,用于一对多依赖关系中的解耦。对象可以通过注册,成为观察者(Observer),去订阅中心对象(Subject)的变化。Subject(被观察者)则需要实现观察者注册、数据更新通知、观察者移除三个基础方法。

NSNotification

注册观察者

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notice:) name:@"PostName" object:nil];

- (void)notice:(id)sender { NSLog(@"%@",sender); }

被观察者发出通知

[[NSNotificationCenterdefaultCenter] postNotificationName:@"PostName" object:nil];

移除通知

- (void)dealloc  {

      [[NSNotificationCenter defaultCenter] removeObserver:self name:@"PostName" object:nil];

}

KVO

KVC、KVO小结和应用


代理模式

OC和Swift中的protocol

非正式协议

即Category,如NSString (StringFrame)。

代理与Block

1、block是让代码块以闭包(一个函数+其执行的外部上下文变量)的形式传递内容,实在是太轻量级了,适用于大多数异步和简单的回调。

2、当有多个方法回调时应当选用delegate会更清晰,如UITableView的delegate代理方法。

3、block会涉及到栈区到堆区的拷贝等操作,delegate只是定义了一个方法列表,在遵守了协议的对象的objc_protocol_list中添加了一个节点,运行时向对象发送消息即可。所以block在时间空间消耗都大于delegate,性能消耗较大。

4、代理更加面向过程,block更加面向结果。


策略模式

#结合现金支付计算策略实例详细说明#

1、定义一个抽象的、通用的算法(抽象策略类BaseStrategy)协议,此角色给出所有具体策略类所需的接口;

@protocol CashBase 

-(CGFloat)acceptCash:(CGFloat)cash;

@end

2、让每个具体算法(继承Base的具体策略类NormalStrategy,SpecialStrategy)都遵循他的守则,提供了具体的算法实现了抽象策略类定义的接口;

@interface CashNormal : NSObject <CashBase>

@end

@implementation CashNormal

-(CGFloat)acceptCash:(CGFloat)cash { return cash; }

@end

@interface CaseReturn : NSObject <CashBase>

-(instancetype)initWithMoneyReturn:(CGFloat)moneyReturn;

@end

@implementation CaseReturn     

-(instancetype)initWithMoneyReturn:(CGFloat)moneyReturn {

      if (self) {

           _moneyReturn = moneyReturn;

      }

      return self;

}

-(CGFloat)acceptCash:(CGFloat)cash {

      return cash - self.moneyReturn;

}

@end

3、然后需要定义一个环境角色(Context类)用来持有一个Strategy的引用,配合简单工厂模式,根据入参决定调用哪个具体策略类算法;

@interface CashContext : NSObject

-(instancetype)initWithCashType:(CashType)type;

-(CGFloat)getResult:(CGFloat)money;

@end

@implementation CashContext

-(instancetype)initWithCashType:(CashType)type{

      //根据type初始化算法实例

}

-(CGFloat)getResult:(CGFloat)money{

      //算法实例调用策略接口

      return [self.cashSuper acceptCash:money];

}

@end

4、最后在需要的地方调用Context对象。

CashContext * context = [[CashContext alloc] initWithCashType:CashTypeNormal];

NSLog(@"结果是%f",[context getResult:100]);


装饰模式

不修改原类代码的情况下,动态、透明的给一个对象增加新的行为和职责,Decorator比生成子类更加灵活,其目的是把功能分散,运行期间再动态组合。

装饰器的构成:1、Component,抽象的组件父类,声明了一些方法由子类进行重载;ConcreteComponent,具体的组件类,实现了组件接口,通常是被装饰的原始对象。

2、Decorator,装饰器父类(Component细化后的抽象类),用来持有原对象(被装饰对象)。ConcreteDecorator具体的装饰器类,具体实现要添加的功能,并内嵌Component操作,以装饰具体的组件对象。

在iOS中,分类(category)简单便捷的实现了装饰器设计模式所能达到的功能,但严格意义上讲并不符合装饰器模式的定义。

注:1、有些教程中说委托也是iOS中的一种装饰器模式,但我认为委托没有做到装饰模式定义中“不修改原类代码”的要求;2、分类中定义的方法不要和原有类的方法重名。


软件开发中还用很多常用的设计模式,如模板方法模式(提取算法可复用结构,延迟某些特定步骤到子类:如问答题的不变部分(题目)和变化部分(答案))、外观模式(为一套需要同时调用的子系统定义一个高层的综合接口,便于多个接口同时调用)、建造者模式、状态模式、适配器模式、备忘录模式、组合模式、迭代器模式、单列模式、桥接模式、命令模式、职责链模式、中介者模式、享元模式、解释器模式、访问者模式、原型模式(已有对象深拷贝申请新内存,生成新对象,需满足NSCopying协议)等。

最后提供一下容易乱入的MVC,MVVM等设计模式等链接,严格来说,它们应称为架构设计模式,而非广义上的编码设计模式。

架构设计模式之MVC和MVVM


写在最后

没有最后 <( ̄︶ ̄)>

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

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,884评论 1 15
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    RamboLI阅读 739评论 0 1
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    lichengjin阅读 885评论 0 8
  • 原文链接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤独杂货铺阅读 1,505评论 0 3
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,739评论 3 13