美文网首页
03.设计模式之适配器模式

03.设计模式之适配器模式

作者: 越来越胖了 | 来源:发表于2020-05-09 17:39 被阅读0次

适配器模式,一个经常使用但是不知道叫这个名字的设计模式🤣🤣,开发者经常用,所以细致的学习了一遍,以下是自己的一些总结:

秉承着不给demo的文章不是好程序员的思想:demo,因为百度网盘链接经常失效的原因,把demo改成上传CSDN了,还能赚赚积分😁😁,如果你没有积分,请留言😱

问题:大家经常使用的UITableView是什么设计模式?其实就是适配器模式的非常典型的使用,所以说我们经常使用适配器.

适配器模式主要分为三个角色:

  • 适配器(核心)
  • 目标接口
  • 被适配者
    适配器还可以分为两种:类适配器 和 对象适配器 (后面🌰会讲解)
    以UITableView为例,我们在一个VC中创建使用tableview,那么:
    适配器->ViewController(实现协议->两个delegate)
    目标接口->UI界面(抽象)->UITableView(Cell)
    被适配者->数据(array,model)
适配器模式.png

一句话总结就是:我们通过适配器 把数据适配到UI上进行显示,讲原理还是这么的枯燥,所以下面举两个🍗

栗子一:把传统的美元兑换成我们的人民币:
首先目标接口:

#import <Foundation/Foundation.h>

//目标接口target
@protocol Target <NSObject>

-(float)getRMB;

@end

然后是我们的被适配者,也就是老的功能模块,美元:

#import <Foundation/Foundation.h>

//被适配对象(Adaptee:说白了就是老的功能模块,接口)
@interface Adaptee : NSObject

//美元
-(float)getUSD;

@end
#import "Adaptee.h"

@implementation Adaptee

-(float)getUSD{
    return 1000;
}

@end

下面是最最主要的适配器,这里分两种
1.类适配器:

  • 步骤一:遵从协议,实现接口;
  • 步骤二:继承被适配器;
#import <Foundation/Foundation.h>
#import "Adaptee.h"
#import "Target.h"

/**
 * 类适配器模式
 * 注意:
 * 第一点:类适配器模式Adapter需要继承被适配的类
 
 * 第二点:类适配器模式Adapter需要实现目标接口
 *
 */
@interface Adapter : Adaptee<Target>

@end
#import "Adapter.h"

@implementation Adapter

//这里,适配器,把美元适配成了人民币;
//这里是一个类适配器

-(float)getRMB{
    return [self getUSD] * 7.0f;
}

@end
  1. 对象适配器:
  • 步骤一:遵从协议,实现接口;
  • 步骤二:要有一个被适配器的实例对象
#import <Foundation/Foundation.h>
#import "Target.h"
@class Adaptee;
/**
 * 对象适配器模式
 * 注意:
 * 第一点:不需要继承
 *
 */
@interface ObjectAdapter : NSObject<Target>

-(instancetype)init:(Adaptee*)adaptee;

@end
#import "ObjectAdapter.h"

#import "Adaptee.h"

@interface ObjectAdapter ()

@property (nonatomic,strong)Adaptee* adaptee;

@end

@implementation ObjectAdapter

- (instancetype)init:(Adaptee*)adaptee{
    self = [super init];
    if (self) {
        _adaptee = adaptee;
    }
    return self;
}

-(float)getRMB{
    return [_adaptee getUSD] * 7.0f;
}

@end

是的,就是这么简单,我们通过适配器,把我们被适配的美元转成了人民币;
可能这个例子不够形象,下面用我们的tableView举例:
1.创建我们的适配器

  • 实例化一个被适配器对象,被适配器对象是 数据,所以这里,创建一个dataArray;
  • 要遵从协议,去实现接口-->这里就是 UITableViewDelegate,UITableViewDataSource的协议方法了-->UI
#import <UIKit/UIKit.h>

/**
 这里这个是适配器:--->且是一个对象适配器
 
 1.实例化一个被适配器对象,被适配器对象是 数据,所以这里,创建一个dataArray
 
 2.要遵从协议,去实现接口-->这里就是 UITableViewDelegate,UITableViewDataSource的协议方法了-->UI
 
 */


@interface BaseAdapter : NSObject<UITableViewDelegate,UITableViewDataSource>

@property (nonatomic,strong) NSMutableArray *dataArray;

@end
#import "BaseAdapter.h"

@implementation BaseAdapter

- (instancetype)init{
    self = [super init];
    if (self) {
        _dataArray = [[NSMutableArray alloc] init];
    }
    return self;
}


//这里提供默认的实现,子类可以重写;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _dataArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString * cellIdentifier = @"cellIdentifier";
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                      reuseIdentifier:cellIdentifier];
    }
    return cell;
}

这里给出默认的实现,子类可以重写,可以达到很好的复用性;dataarray就是我们的被适配者,我们给数据创建一个model,把数据存储在model中

#import <Foundation/Foundation.h>

@interface UserModel : NSObject

@property (nonatomic,copy) NSString *title;
@property (nonatomic,copy) NSString *name;

-(instancetype)initWithTitle:(NSString*)title name:(NSString*)name;

@end
#import "UserModel.h"

@implementation UserModel

- (instancetype)initWithTitle:(NSString*)title name:(NSString*)name{
    self = [super init];
    if (self) {
        _title = title;
        _name = name;
    }
    return self;
}

@end

然后,我们去创建一个适配器的子类,这样就可以进行我们自己的定制了

#import "BaseAdapter.h"

@interface UserAdapter : BaseAdapter

@end
#import "UserAdapter.h"
#import "UserModel.h"

/*
 这里就是对适配器的子类化,可以重写实现的接口,达到BaseAdapter的可复用性;
 */

@implementation UserAdapter

- (instancetype)init{
    self = [super init];
    if (self) {
        //模拟的假数据
        [self.dataArray addObject:[[UserModel alloc] initWithTitle:@"姓名" name:@"Dream"]];
        [self.dataArray addObject:[[UserModel alloc] initWithTitle:@"国家" name:@"中国"]];
        [self.dataArray addObject:[[UserModel alloc] initWithTitle:@"语言" name:@"中文"]];
    }
    return self;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return [super numberOfSectionsInTableView:tableView];//这里我们采用了默认的处理,比如有各种条件,也可以自己定义
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [super tableView:tableView numberOfRowsInSection:section];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
    UserModel* model = [self.dataArray objectAtIndex:indexPath.row];
    cell.textLabel.text = model.title;
    cell.detailTextLabel.text = model.name;
    return cell;
}

当然这里,我把UITableViewDelegate,UITableViewDataSource放在了一个适配器中,也可以分开用两个子适配器去写;
这样,我们的tableView只需要设置它的两个代理就可以了:

#import "ViewController.h"
#import "Adapter.h"
#import "UserAdapter.h"
/**
 适配器 --> ViewController
 目标接口--> UI界面(UITableView,UITableViewCell)
 陪适配者--> 我们的数据
 */
@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>

/**
 这里的tableVIew也是可以定制的,比如有特定的刷新动画,但是他不属于adpater
 */


@property (weak, nonatomic) IBOutlet UITableView *tableView;

@property (nonatomic) UserAdapter* adapter;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //客户端调用
//    Adapter* adapter = [[Adapter alloc] init];
//    float rmb = [adapter getRMB];
//    NSLog(@"人名币:%f",rmb);
    
//    [self initTableView];
    [self initAdapter];
    
    
}

//原始代码结构方式
-(void)initTableView{
    _tableView.delegate = self;
    _tableView.dataSource = self;
}

//新的代码结构方式
-(void)initAdapter{
    _adapter = [[UserAdapter alloc] init];
    _tableView.delegate = _adapter;
    _tableView.dataSource = _adapter;
}
//
//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
//    return 1;
//}
//
//- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectio{
//    return 10;
//}
//
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//    static NSString * showUserInfoCellIdentifier = @"userInfoCell";
//    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:showUserInfoCellIdentifier];
//    if (cell == nil){
//        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
//                                       reuseIdentifier:showUserInfoCellIdentifier];
//    }
//    cell.textLabel.text=@"姓名";
//    cell.detailTextLabel.text = @"Dream";
//    return cell;
//}


@end

这样,我就就很好的解决了VC代码臃肿的问题,同时,代码的复用性高,可维护性强,再也不是把tableView一股脑的写在一个VC中了;
以前刚接触iOS时,我对_tableView.delegate = _adapter;_tableView.dataSource = _adapter;不大理解,怎么把类给到了一个代理,所以这里也给大家解释一下协议和抽象基类,懂得就略过了:

协议和抽象基类

协议,不定义任何实现,只声明方法,以确定符合协议的类的行为,因此,协议只是定义了抽象行为的接口,实现协议的类定义这些方法的实现,以执行真正的操作;
另一种定义高度抽象类型的方法是抽象基类(ABC),通过抽象基类,我们可以生成其他子类可以共享额默认行为,抽象基类和通常的类相似.只是预留了可以由子类重载的行为;

id<Delegate> myDelegate 这样的指针可以指向任何Delegate对象,这是非常强大,方便且灵活,你不用关心对象是什么类型,而只关心它实现了哪些方法

这样看起来,为什么有了抽象基类还要弄个协议出来呢?因为IOS没有多继承,但是可以遵从多个协议;

协议的本质也是一个id类型的类,我们定义一个协议使用的是:id<Delegate> myDelegate,id<Delegate> 告诉编译器你不关心对象是什么类型,但它必须遵守Delegate协议,编译器就能保证所有赋值给id<NSObject>类型的对象都遵守NSObject协议,这就是为什么我们在给一个类设置代理时,如果不写<Delegate> 而直接使用代码 self.delegate = self;时会有警告;

后期会更新MVC MVP MVVM中 适配器的使用,下班了.....

相关文章

  • 简说设计模式之适配器模式

    前言:对于设计模式基础概念可以去看[简说设计模式之设计模式概述] 一、什么是适配器模式 适配器模式(Adapter...

  • 03.设计模式之适配器模式

    适配器模式,一个经常使用但是不知道叫这个名字的设计模式??,开发者经常用,所以细致的学习了一遍,以下是自己的一些总...

  • 设计模式 - 目录

    设计模式01 - 单例模式 设计模式02 - 工厂模式 设计模式03 - 建造者模式 设计模式04 - 适配器模式...

  • 设计模式详解——适配器模式

    本篇文章介绍一种设计模式——命令模式。本篇文章内容参考《JAVA与模式》之适配器模式,Android设计模式源码解...

  • 设计模式之适配器模式

    设计模式之适配器模式 1. 模式定义 适配器模式又称包装器模式,属于结构型模式,它可以将一个接口转换成客户希望的另...

  • 最常用的设计模式---适配器模式(C++实现)

    适配器模式属于结构型的设计模式,它是结构型设计模式之首(用的最多的结构型设计模式)。 适配器设计模式也并不复杂,适...

  • iOS设计模式(5)策略模式

    设计模式系列文章 《iOS设计模式(1)简单工厂模式》《iOS设计模式(2)工厂模式》《iOS设计模式(3)适配器...

  • iOS设计模式(6)模板模式

    设计模式系列文章 《iOS设计模式(1)简单工厂模式》《iOS设计模式(2)工厂模式》《iOS设计模式(3)适配器...

  • iOS设计模式(7)建造者模式

    设计模式系列文章 《iOS设计模式(1)简单工厂模式》《iOS设计模式(2)工厂模式》《iOS设计模式(3)适配器...

  • iOS设计模式(4)抽象工厂模式

    设计模式系列文章 《iOS设计模式(1)简单工厂模式》《iOS设计模式(2)工厂模式》《iOS设计模式(3)适配器...

网友评论

      本文标题:03.设计模式之适配器模式

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