美文网首页
iOS设计模式三(中介者,观察者)

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

作者: oldSix_Zhu | 来源:发表于2017-01-30 18:34 被阅读121次

    承接上文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
    

    相关文章

      网友评论

          本文标题:iOS设计模式三(中介者,观察者)

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