美文网首页
在iOS中理解设计模式

在iOS中理解设计模式

作者: 六横六竖亚 | 来源:发表于2017-07-14 16:55 被阅读8次

    设计模式即编码的工程化,是代码设计经验的总结。使用设计模式可提高代码的复用性、可读性和可靠性。设计模式在各类面向对象的语言中基本相通,仅在具体的实现语法上略有差异,下面我们以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小结和应用


    代理模式

    iOS中的代理是由协议(@Protocol)、代理对象(id delegate)和委托者(<delegate>)三部分组成。

    协议

    @protocol TestDelegate <NSObject, OtherDelegate>   //协议可多继承

    @required //必须实现的方法(默认)

    @option //可选实现的方法

    - (void) test; //定义一个方法

    @end

    代理对象

    代理对象使用weak修饰,防止委托者被受委托者持有造成循环引用、内存泄露。

    @property (nonatomic, weak) id <TestDelegate> delegate;

    if ([self.delegate respondsToSelector:@selector(test)]) { //判断协议方法是否被实现

          [self.delegate test];

    }

    委托者

    <TestDelegate>  //服从协议

    .delegate = self; //指定代理对象

    - (void) test {}  //实现协议中的方法

    非正式协议

    即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


    写在最后

    没有最后 <( ̄︶ ̄)>

    相关文章

      网友评论

          本文标题:在iOS中理解设计模式

          本文链接:https://www.haomeiwen.com/subject/ohdnhxtx.html