iOS设计模式三(中介者,观察者)

承接上文iOS设计模式二(适配器,桥接,外观)
本文为去耦合--获取源码

目录
1.中介者模式
2.观察者模式


1.中介者模式

中介者模式用一个中介者,定义一个集中的场所,使对象间的交互可以在这个场所内集中处理,其他对象可以互相交互而不必彼此依赖,达到解耦的目的

飞机,汽车通过一个GPS控制台互相知晓位置的例子:
(OSZ为oldSixZhu缩写)

首先,我们需要飞机,这里定义一个飞机基类就可以了.
OSZPlane.h:

#import <Foundation/Foundation.h>
#import "OSZMediatorManager.h"
@interface OSZPlane : NSObject
//名字
@property (nonatomic, copy) NSString *name;
//位置
@property (nonatomic, assign) CGPoint location;
//中介者
@property (nonatomic, strong) OSZMediatorManager *mediator;

//告诉控制台(中介者)自己的位置
- (void)sendSelfLocation;
//从控制台(中介者)知道别人的位置
- (void)getOtherLocation:(id)plane;
@end

OSZPlane.m:

#import "OSZPlane.h"
@implementation OSZPlane
- (void)sendSelfLocation
{
    [self.mediator getObjLocation:self];
}
- (void)getOtherLocation:(id)plane
{
    NSString *location = [self.mediator sendObjLocation:plane];
    NSLog(@"位置为%@",location);
}
@end

再定义三个子类,OSZPlaneA,OSZPlaneB,OSZPlaneC,
都可以重写或者重载基类的方法,加一些特有的逻辑,这个例子里就不动了

还需要一个地勤车,也可以是基类,方法与飞机方法相同即可
OSZSignalCar.h:

#import <Foundation/Foundation.h>
#import "OSZMediatorManager.h"
@interface OSZSignalCar : NSObject
//名字
@property (nonatomic, copy) NSString *name;
//位置
@property (nonatomic, assign) CGPoint location;
//中介者
@property (nonatomic, strong) OSZMediatorManager *mediator;

//告诉控制台(中介者)自己的位置
- (void)sendSelfLocation;
//从控制台(中介者)知道别人的位置
- (void)getOtherLocation:(id)car;
@end

OSZSignalCar.m:

#import "OSZSignalCar.h"
@implementation OSZSignalCar
- (void)sendSelfLocation
{
    [self.mediator getObjLocation:self];
}
- (void)getOtherLocation:(id)car
{
    NSString *location = [self.mediator sendObjLocation:car];
    NSLog(@"位置为%@",location);
}
@end

也可以创建几个子类,更好地扩展,这个例子就不做了

接下来是中介者(mediator):
OSZMediatorManager.h:

#import <Foundation/Foundation.h>
#import "singleton.h"

//#import "OSZPlaneA.h"
//#import "OSZPlaneB.h"
//#import "OSZPlaneC.h"
@class OSZPlaneA;
@class OSZPlaneB;
@class OSZPlaneC;
@class OSZSignalCar;

@interface OSZMediatorManager : NSObject

//存储各飞机位置信息
@property (nonatomic, strong) OSZPlaneA *planeA;
@property (nonatomic, strong) OSZPlaneB *planeB;
@property (nonatomic, strong) OSZPlaneC *planeC;
@property (nonatomic, strong) OSZSignalCar *car;

//接收plane位置信息
- (void)getObjLocation:(id)obj;

//发送plane位置信息
- (NSString *)sendObjLocation:(id)obj;

////直接返回飞机的全部信息
//- (id)sendPlane:(id)plane;

//保证只有一个中介者(见iOS设计模式一单例模式宏)
singleton_h(OSZMediatorManager)

@end

OSZMediatorManager.m:

#import "OSZMediatorManager.h"
#import "OSZPlaneA.h"
#import "OSZPlaneB.h"
#import "OSZPlaneC.h"
#import "OSZSignalCar.h"
@implementation OSZMediatorManager
//单例模式宏
singleton_m(OSZMediatorManager)

- (void)getObjLocation:(id)obj
{
    if ([obj isKindOfClass:[OSZPlaneA class]])
    {
        self.planeA = obj;
    }
    else if ([obj isKindOfClass:[OSZPlaneB class]])
    {
        self.planeB = obj;
    }
    else if ([obj isKindOfClass:[OSZPlaneC class]])
    {
        self.planeC = obj;
    }
    else if ([obj isKindOfClass:[OSZSignalCar class]])
    {
        self.car = obj;
    }
    else
    {
        NSLog(@"不是管辖范围内的飞机");
    }
}

//可以选择有返回值的方法
- (NSString *)sendObjLocation:(id)obj
{
    if ([obj isKindOfClass:[OSZPlaneA class]])
    {
        NSString *location = NSStringFromCGPoint(self.planeA.location);
        return location;
    }
    else if ([obj isKindOfClass:[OSZPlaneB class]])
    {
        NSString *location = NSStringFromCGPoint(self.planeB.location);
        return location;
    }
    else if ([obj isKindOfClass:[OSZPlaneC class]])
    {
        NSString *location = NSStringFromCGPoint(self.planeC.location);
        return location;
    }
    else if ([obj isKindOfClass:[OSZSignalCar class]])
    {
        NSString *location = NSStringFromCGPoint(self.car.location);
        return location;
    }
    else
    {
        NSLog(@"不是管辖范围内的飞机");
        return 0;
    }
}
@end

控制器OSZSixVC.m:

#import "OSZSixVC.h"
#import "OSZMediatorManager.h"
#import "OSZPlaneA.h"
#import "OSZPlaneB.h"
#import "OSZPlaneC.h"
#import "OSZSignalCar.h"

@interface OSZSixVC ()

@end

@implementation OSZSixVC

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor redColor];
    OSZMediatorManager *mediator = [[OSZMediatorManager alloc]init];
    
    OSZPlaneA *a = [[OSZPlaneA alloc]init];
    a.name = @"飞机a";
    a.location = CGPointMake(100, 100);
    a.mediator = mediator;
    
    OSZPlaneB *b = [[OSZPlaneB alloc]init];
    b.name = @"飞机b";
    b.location = CGPointMake(200, 200);
    b.mediator = mediator;
    
    OSZPlaneC *c = [[OSZPlaneC alloc]init];
    c.name = @"飞机c";
    c.location = CGPointMake(300, 300);
    c.mediator = mediator;
    
    //三者通过把自身的信息发送给中介者,
    //达到了互相联系但不互相引入头文件
    //若是互相引入头文件会越来越乱,方法也会重复
    //但是把处理逻辑都集中在了中介者身上,中介者就会变得复杂
    [a sendSelfLocation];
    [b sendSelfLocation];
    [c sendSelfLocation];
    
    [a getOtherLocation:b];//位置为{200, 200}
    [a getOtherLocation:c];//位置为{300, 300}
    
    [b getOtherLocation:a];//位置为{100, 100}
    [b getOtherLocation:c];//位置为{300, 300}
    
    [c getOtherLocation:a];//位置为{100, 100}
    [c getOtherLocation:b];//位置为{200, 200}
    
    //当我们继续扩展,加一个地勤信号车与三个飞机通讯的时候
    //只需要在中介者中改改就好了,很方便
    //扩展性很好
    OSZSignalCar *car = [[OSZSignalCar alloc]init];
    car.name = @"飞机b";
    car.location = CGPointMake(200, 200);
    car.mediator = mediator;
    
    [car sendSelfLocation];
    [car getOtherLocation:a];//位置为{100, 100}
    [car getOtherLocation:b];//位置为{200, 200}
    [car getOtherLocation:c];//位置为{300, 300}
}
@end

我们看到,方法的整体是一个中型的if-else语句块,如果是巨型的switch-case或者if-else就应该考虑使用别的算法,如策略模式,接下来我会更新.
因此酌情使用吧

扩展:
Mediator(中介者)模式在iOS开发当中的使用
iOS 设计模式 - 中介者模式
iOS设计模式之中介者模式
iOS设计模式——中介者模式


2 观察者模式

观察者模式也叫做发布-订阅模式,可以用通知和KVO(Key Value Observing)两种方法来实现.

通知的使用就不多说了,典型的一对多时使用,当然,一对一使用也可以.

- (void)postNotification{
    NSNotification *notification = [NSNotification notificationWithName:@"nslog" object:self];
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(nslog) name:@"nslog" object:self];   
    [center postNotification:notification];
}

- (void)nslog{
    NSLog(@"通知触发调用的方法");
}

一个很常见的KVO监听tableView滚动,改变头视图透明度的例子:
控制器OSZSevenVC.m:

#import "OSZSevenVC.h"
@interface OSZSevenVC ()<UITableViewDelegate>
@property (weak , nonatomic)UITableView *userVCTableView;
@property (weak , nonatomic)UIView      *alphaView;
@end

@implementation OSZSevenVC
- (void)viewDidLoad
 {
    [super viewDidLoad];
    [self setupUI];
    /* tableViewController 观察 tableView 的 contentOffset */
    [self.userVCTableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:@"JDUserVCContext"];
}
//不移除会崩溃
-(void)dealloc
{
    [self.userVCTableView removeObserver:self forKeyPath:@"contentOffset" context:@"JDUserVCContext"];
}
-(void)setupUI
{
    UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
    //保存tableview
    self.userVCTableView = tableView;
    self.userVCTableView.delegate = self;
    [self.view addSubview:self.userVCTableView];
    
    //头视图
    UIView *barView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, 64)];
    barView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:barView];
    
    UIView *alphaView = [[UIView alloc]initWithFrame:barView.frame];
    alphaView.backgroundColor = [UIColor blueColor];
    alphaView.alpha = 0;
    self.alphaView = alphaView;
    [barView addSubview:alphaView];
}

//当观察者的观察对象的属性一发生变化时, 就调用这个方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([object isEqual:self.userVCTableView] && [keyPath isEqualToString:@"contentOffset"])
    {
        CGPoint offset = self.userVCTableView.contentOffset;
        /* 那么我先算出头视图的高度 */
        CGFloat cycleScrollViewHeight = kScreenWidth * 120 / 300;
        /* 用 offset 值比上头视图的高度,那么,当轮播滚动范围的 y 值等于轮播图的高度时, navigationBar 就完全不透明了 */
        CGFloat alpha = MIN(1, fabs(offset.y / cycleScrollViewHeight));
        /* 设置实时透明度 */
        self.alphaView.alpha = alpha;
    }
}
@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容