ios设计模式——适配器模式

2019-01-15  本文已影响0人  小书同学

一、什么是适配器?

  举个例子,我们有些人买手机,买的是港版,会发现港版的电源插头跟我们的不一样,基本都是三角,而且它的三角还跟国内的不一样,导致我们必须用一个转换头才行。为了让港版电源插头在国内也能使用,就用转换头,这个转换头就是适配器。
  在开发过程中,我们会遇到旧代码与新接口无法兼容的问题,这时候,引入适配器,就可以实现新接口调用旧代码的功能。

二、适配器模式(Adapter Pattern)

适配器模式,就是使得原本由于接口不兼容而不能一起工作的类可以一起工作。简单的说,适配器模式就是是用来解决使用不兼容接口的问题的方案

1、类适配器

这种适配器模式,就是通过继承来适配两个接口。
在Objective-C中,有protocol,我们可以通过实现protocol,同时又继承超类,达到多重继承的效果。

类适配器.png

Target : protocol协议,也就是目标接口,或称为标准接口
Adaptee :父类,也就是被适配者。一个已经存在的,具有某种需要的特殊功能,但又不符合我们既有的标准接口的类。

  图中,Adapter实现了协议Target,同时又继承了父类Adaptee。这样就让Adapter既是一个Target类型,也是一个Adaptee类型。在Adapter中,实现了协议Target中的request()方法,没有重载Adaptee的方法,而是在request()方法中,执行[super specificRequest]。这样就达到了,通过一个目标接口的调用,去使用一个已有的某个功能。

//Target.h
@protocol Target <NSObject>
- (void)request;
@end
//Adaptee.h
@interface Adaptee : NSObject
- (void)specificRequest;
@end
//Adapter.h
@interface Adapter : Adaptee <Target>
@end
//Adapter.m
@implementation Adapter
- (void)request{
    NSLog(@"Adapter request()");
    [super specificRequest];
}
@end

  类适配器的重点是类的继承,这样我们的适配器可以根据需求去创建需要的子类类型。

2、对象适配器

  对象适配器与上面的类适配器有所不同,对象适配器不需要继承被适配者,而是组合一个对它的引用。


对象适配器.png

这个图跟上面的类适配器的图相似,只是Adapter与Adaptee之间的关系不再是继承,而是包含关系。在这种关系中,Adapter中保持了一个队Adaptee的引用。这样在Adapter的request()方法中,直接使用[adaptee specificReuqest],以此间接的访问Adapteede的方法。

//NewAdapter.h
@interface NewAdapter : NSObject<Target>
@end
//NewAdapter.m
@interface NewAdapter()
@property (nonatomic, strong) Adaptee *adaptee;
@end
@implementation NewAdapter
- (void)request{
    [_adaptee specificRequest];
}
@end

3、差别

  类适配器对象适配器是实现适配器模式的两种不同方式,但是达到的目的都是一样的。那么两者有什么差别了?

类适配器
  1、需要创建Adaptee的子类,所以只针对单一的具体的Adaptee类,把Adaptee适配到Target;
  2、由于创建了子类,可以重载Adaptee的方法;
  3、由于是Adaptee的子类,可以直接访问Adaptee。

对象适配器
  1、可以适配多个Adaptee及其子类;
  2、难以重载Adaptee的方法,需要借助于Adaptee的子类,而不是Adaptee本身;
  3、需要额外的指针来间接访问Adaptee或其方法。

4、何时使用适配器模式

1、已有类的接口与需求不匹配;
2、想要一个可复用的类,该类能够同可能带有不兼容接口的其他类协同工作。
3、需要适配一个类的几个不同子类,可是让每一个子类去子类化一个类适配器又太麻烦,可以使用对象适配器来适配其父类的接口。

三、委托Delegate

  我们在iOS开发过程中,最常见的就是delegate,比如需要实现UITableView的时候,我们会用到UITableViewDelegate。
  我们理理这个delegate。使用过程中,我们不需要知道UITableView中是如何调用这个delegate的,只需要在对应需要显示UITableView的地方实现UITableViewDelegate这个协议,而UITableView也不需要知道是如何实现具体的内容的。这样两者的关联通道仅仅是一个delegate而已。
  接下来,用平时的代码来自定义一个delegate。

@protocol btnClickedDelegate <NSObject>
//  定义了一个UITablViewCell中Button被点击的delegate
-(void)cellBtnClicked:(NSInteger)section row:(NSInteger)row;
@end

接着在Controller中实现了对应protocol

@interface TestViewController ()<UITableViewDelegate,UITableViewDataSource,btnClickedDelegate>{
        NSString *_cellIdentifier;
}
@end

@implementation NoviceGuideViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    TestTableViewCell *cell = (TestTableViewCell *)[tableView dequeueReusableCellWithIdentifier:_cellIdentifier];
    cell.delegate = self; //传递delegate到cell中
    return cell;
}
- (void)cellBtnClicked:(NSInteger)section row:(NSInteger)row{
    // 省去实现的代码
}
@end

适配器实现了,那么就是被适配者的回调
.h文件

@interface TestTableViewCell : UITableViewCell
@property (weak, nonatomic) id<btnClickedDelegate> delegate;
@end

.m文件

- (IBAction)buttonClick:(id)sender {
    if(self.delegate && [self.delegate respondsToSelector:@selector(cellBtnClicked:row:)]){
        [self.delegate cellBtnClicked:section row:row];
    }
}

  这样,整个逻辑就完成了。
  梳理一下执行流程:当cell中的按钮被点击的时候,会通过cell中的delegate,去调用cell中的引用,也就是Controller,然后controller中对对应的协议的实现,就是其后续的自己的逻辑流程了。

四、用Objective-C的块

  只需将上面的delegate换成block就可以了。
只是有几个地方需要注意:
1、就是controller不在需要实现delegate了;
2、controller中直接声明block,传递给cell;
3、cell中仍然持有对block的引用;
4、cell中直接对block进行调用。

上一篇下一篇

猜你喜欢

热点阅读