iOS --设计模式(2、观察者模式)

观察者模式的定义:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新!
提到观察者,你想到的很可能是KVO,是

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;``` 
 方法
还有可能顺带想到一对多原则的通知。

观察者模式,并不是OC中所说的KVO与通知。但其实现思路确与二者的底层实现相一致:被观察者通知观察者有数据更新,并将数据告知观察者。其并不关心谁是观察者,有多少观察者,而观察者也无需知道被观察者是如何获取数据更新的。

下面模拟以下场景:

某气象站有这样一套设置:可以实时地监测环境的温度(temperature)、湿度(humidity)和气压(pressure),并有一套与之相连接的SDK(YXWWeatherDataSDK),可以实时返回这三个参数.现需要做一个气象观测站:首先,做一款App,以这三个参数互相组合展示三个页面(当前气象、温差显示及天气预报),再者,该观测站必须公布一组API可让第三方调用。

在做App时,如果三个页面者直接使用气象站的SDK,这样一旦SDK更新时,其参数的类型、数量等发生变化或者直接更换了SDK,那将带来非常繁琐的工作量。

不再多说,直接上代码。我们首先创建subject主题接口,用来声明注册、移除、通知观察者,所有的被观察者必须实现此接口。

import

@protocol WYXSubject
@requried

  • (void)registerObserver:(id)obj;
  • (void)removeObserver:(id)obj;
  • (void)notifyObervers:(NSDictionary *)data;

@end```

创建Observer观察者接口,所有的观察者要实现此接口

#import 

@protocol WYXObserver 

- (void)update:(NSDictionary *)data;

@end

创建DisplayElement接口,观察者应实现此接口,在需要更新页面时调用相应方法

#import 

@protocol WYXDisplayElement 

- (void)display;

@end```

下面实现被观察者
新建 WYXWeatherData 类,该类遵守WYXSubject协议

import

import "WYXSubject.h"

@interface WYXWeatherData : NSObject

  • (instancetype)sharedWeatherData;

@end

再看下具体实现
在单例方法中,该类成为YXWWeatherDataSDK的代理并实现代理方法

import "WYXWeatherData.h"

import "YXWWeatherData.h"

import "WYXObserver.h"

import "WYXHeaders.h"

@interface WYXWeatherData ()
// 用来存放观察者
@property (nonatomic, strong) NSMutableArray >*observersArr;

@end

@implementation WYXWeatherData

static WYXWeatherData *weatherData;

  • (instancetype)sharedWeatherData{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    weatherData = [[WYXWeatherData alloc] init];
    weatherData.observersArr = [NSMutableArray array];
    // 设置代理
    [YXWWeatherData sharedWeatherDataSDK].delegate = weatherData;
    });
    return weatherData;
    }
    }```
    其中observersArr用来存放观察者。
    然后实现WYXSubject协议方法

pragma mark ****** WYXSubjec ******

// 添加观察者
- (void)registerObserver:(id)obj{
    [self.observersArr addObject:obj];
}

// 移除观察者
- (void)removeObserver:(id)obj{
    for (idoberver in self.observersArr) {
        if ([oberver isEqual:obj]) {
            [self.observersArr removeObject:obj];
        }
    }
    
}
// 通知观察者有更新
- (void)notifyObervers:(NSDictionary *)data{
    for (idoberver in self.observersArr) {
        [oberver update:data];
    }
    
}```
在代理方法中调用上述- (void)notifyObervers:(NSDictionary *)data方法来为观察者更新数据

pragma mark ****** delegate ******

  • (void)updateTemperature:(float)temperature humidity:(float)humidity andPressure:(float)pressure{
    NSDictionary *data = @{
    TEMP : @(temperature),
    HUMI : @(humidity),
    PRES : @(pressure)
    };
    [self notifyObervers:data];
    }```

以上代码就可以视为我们所需要提供给第三方的API。
下面我们通过上述API来实现当前气象的的页面。
新建WYXCurrCondiDisplay类

#import 
#import "WYXObserver.h"
#import "WYXDisplayElement.h"
#import "WYXSubject.h"

@interface WYXCurrCondiDisplay : NSObject
// 构造方法需要一个实现Suject协议的被观察者对象
- (instancetype)initWithWeatherData:(id)weatherData;

@end```

import "WYXCurrCondiDisplay.h"

import "WYXHeaders.h"

@interface WYXCurrCondiDisplay ()

@property (nonatomic, strong) NSDictionary *currData;

@end

@implementation WYXCurrCondiDisplay

  • (instancetype)initWithWeatherData:(id)weatherData{
    self = [super init];
    if (self) {
    // 在构造方法中注册成为weatherData的观察者
    [weatherData registerObserver:self];
    }
    return self;
    }
    // 接收到有数据更新的通知

  • (void)update:(NSDictionary *)data{
    self.currData = data;
    [self display];
    }
    // 显示当前数据

  • (void)display{
    float tem = [[self.currData objectForKey:TEMP] floatValue];
    float hum = [[self.currData objectForKey:HUMI] floatValue];
    float pre = [[self.currData objectForKey:PRES] floatValue];

    NSLog(@"当前最新气况\n 温度:%f\n 湿度:%f\n 气压:%f",tem,hum,pre);
    }

[原码地址](https://git.oschina.net/handanying/ObserverPattern.git)

你可能感兴趣的:(iOS --设计模式(2、观察者模式))