IOS设计架构模式:适配器模式和观察者模式

一、适配器模式:

        1、提出问题

        朋友们在开发中有没有遇到过这种情况:开发中写了一个视图控件,虽然这个控件只是一个展示类的,并没有什么交互。但是在项目好几个地方都用到了这个控件了,你在给这个视图控件赋值的时候是怎么做的呢?是不是这么写的呢?

- (void)loadModel:(Model *)model;

这么写没有错,而且感觉很简单。但是有两点不好:1)视图根数据模型有耦合,视图类引入了模型。2)当你在项目里其他的地方用到了这个视图类,而且对应的模型不再是Model了,而是一个新的模型,比如说NewModel,这个时候你要再写一个初始化方法吗?类似:

- (void)loadModel:(NewModel *)model;

这样写似乎也没有错,但是如多更多地方用了怎么办?你有没有想过,我不同的地方用到一个控件,为什么要改写好的视图控件呢?有没有别的方法能让我写的视图控件独立出来,不和数据模型产生耦合呢?这就用到了设计模式中的一个适配器模式了。

        2、定义:将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

        3、使用场景:1)已经存在的类的接口不符合我们的需求; 2)创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;3)在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。

         4、适配器分类:类适配器、对象适配器

         类适配器是针对每一个数据类创建一个适配器。创建的这个适配器类继承于上面的那个被适配的对象。如果要适配另一个数据类就需要再新建一个新的适配器类来适配。类适配器UML图如下:

IOS设计架构模式:适配器模式和观察者模式

        对象适配器是只创建一个适配器类,依赖于上面的适配者。然后根据不同的数据类返回不同的数据。对象适配器UML图如下:

IOS设计架构模式:适配器模式和观察者模式

        5、例子:项目中有一个视图类,展示一个效果,上面是一个灰色View、中间一个用户名UILable,下面一个密码UILable,这个控件在项目中多次使用,并且对应不同的数据模型。

          第一步 声明一个协议

IOS设计架构模式:适配器模式和观察者模式

       第二步 创建根适配器类:类遵守上面的协议,并实现协议的方法,但是只是空实现

IOS设计架构模式:适配器模式和观察者模式

IOS设计架构模式:适配器模式和观察者模式

        第三步:针对新模型数据类,创建适配器

IOS设计架构模式:适配器模式和观察者模式

电视机放上来的肌肤

        第四步:修改视图接收数据方法:把视图控件的初始化数据改为接收一个遵守某个协议的数据

IOS设计架构模式:适配器模式和观察者模式

抗衰老的肌肤是离开的肌肤

        第五步:使用适配器

IOS设计架构模式:适配器模式和观察者模式

看来是急疯了似的

        demo链接地址:https://github.com/GengbinZ/AdapterDemo

       美金换算人民币demo链接地址:https://github.com/GengbinZ/AdapterCNY           

 

二、观察者模式

        

关于观察者模式,我们百度百科一下,会找到:

  观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

IOS设计架构模式:适配器模式和观察者模式

在这个图示例中,"订阅书刊的用户"需要向"书刊发行机构"提供基本的注册信息,这些信息包括用户自己的基本信息和要"订阅的书刊号",然后确定成为" 书刊发行机构"的用户,然后当"书刊发行机构"开始发行书刊,就会根据"订阅书刊的用户"的已经提供过的基本信息,进行发行书刊。然后"订阅书刊的用户" 就会得到相应的书刊。

  在这个"发行-订阅"的模式中,"书刊发行机构"和"订阅书刊的用户"之间是靠"订阅书刊的用户"提供的基本有效的信息建立联系的。

  这个"发行-订阅"的模式也是一种观察者模式的一个生活中非常生动的例子。"书刊发行机构"相当于观察者模式中的一个"通知中心"的角色,会根据实际需求根据用户信息向用户发送消息,然后用户作为观察者收到这些消息之后,就会自动的根据消息来执行自己的业务逻辑。

  接下来,我们要实现通知中心的抽象设计

  根据需求分析,首先我们需要一个唯一的"书刊发行机构",然后可以增加和删除书刊,同时能存储多个书刊,然后每个书刊又可以对应多个"订阅书刊的用户",

   另外要补充一个就是,在添加和移除用户的接口中,我们需要传入用户信息对象,这个用户信息对象我们需要用协议来约束它,我们思考一下,比如订阅书刊,我 们当然需要用户最基本的两个信息,用户的ID和用户订阅的书刊号,用户的ID用于"书刊发行机构"能够准确的发消息或者发书刊正确无误的发对了人,这个作 用就好比我们唯一的身份证号码的作用是一样的。然后用户订阅的书刊号,就能保证"书刊发行机构"能把正确的书刊发到用户手中,不能随便什么书刊都发向随便 什么人的吧。

  所以先写出下面所有的公开的接口,后面再具体实现它们,这就是面向接口设计:

IOS设计架构模式:适配器模式和观察者模式

       另外,当"书刊发行机构"有了新的书刊的时候,根据需求,创建一个书刊号,然后如果有新的用户需要订阅新的书刊,根据需求,创建一个用户订阅书刊的信息对象。

  一个书刊对应每个月会在某一天发布新书,当"书刊发行机构"的现有的书刊有了新的书发布的时候,就会发消息通知订阅这个书刊的用户,然后用户会做出及时的响应回馈。

  按照观察者模式,被观察者发送消息,观察者收到消息就需要立马做出响应。这个和我们之前用的Cocoa框架已经实现的KVO和通知的模式是一样的。

  为了实现这样的模式,我们还需要给用户信息对象用一个协议来约束它:

IOS设计架构模式:适配器模式和观察者模式

接着我们为上面的公开的接口具体实现,但是我们需要选择一个数据结构来存储书刊号和订阅书刊的用户信息对象,这里我选择使用NSMutableDictionary的Key-Value来存储书刊号和书刊,用NSHashTable来存储用户信息对象。

  那么为什么要用NSHashTable来存储用户信息呢?为什么不用别的数据结构,比如数组(NSMutableArray)或者字典(NSMutableDictionary).

    因为NSHashTable会对添加进的对象持有弱引用,当添加进来的元素,外部对他持有的强引用都取消的时候,这个对象就会自动从内存中消除,这样就不需要手动移除这些对象。

    这个相比Cocoa给我们实现的KVO和通知,就不需要我们手动去操作实现removeObserve方法了。

    虽然说,在使用NSHashTable实现的观察者模式,观察者对象本身就至少需要一个强引用,但是在实际开发中,观察者往往都至少会有一个强引用的。

    所以,使用NSHashTable对系统算是一个小小的优化。

IOS设计架构模式:适配器模式和观察者模式

然后接着我们使用前面创造的观察者模式:

  CustomerA.h和CustomerA.m:

IOS设计架构模式:适配器模式和观察者模式

在ViewController中,同时也把ViewController作为用户对象,以self传入:

IOS设计架构模式:适配器模式和观察者模式

打印:

  2016-03-11 14:50:38.980 ObserverPattern[7958:175895] hashTable:NSHashTable {
  [5] <ViewController: 0x7f93d2d26ac0>
  [12] <CustomerA: 0x7f93d2c17f40>
  }
  2016-03-11 14:50:38.981 ObserverPattern[7958:175895] V1.0  SCIENCE
  2016-03-11 14:50:38.981 ObserverPattern[7958:175895] 
  Hello,My Name is : CustomerA 
    V1.0--SCIENCE

 备份的源码链接: http://pan.baidu.com/s/1eQTnm50 密码: s7su

参考链接:http://www.cnblogs.com/goodboy-heyang/p/5265675.html