iOS设计模式二(适配器,桥接,外观)

承接上文iOS设计模式一(工厂,生成器,单例)
本文为接口适配--获取源码

目录:
1.适配器模式
2.桥接模式
3.外观模式


1.适配器模式

我们想把已有的类用于应用程序的其他地方,
但是新功能需要新接口,且新接口与要复用的现有类不一致,
而我们又不想没完没了的更改现有的类,所以需要一个"适配器"(adapter)

适配器模式可以用于连接两种不同种类的对象(如view与model),有时也称为包装器(wrapper)
实现的方式有两种,一种是通过继承适配接口的类适配器,
一种是通过组合(if-else)方式实现的对象适配器

接下来看一个M层与V层适配的例子:(OSZ为oldSixZhu缩写)
OSZViewAdapterProtocol.h:

//适配器协议
//视图控件的初始化数据接收一个遵守某个协议的数据
#import <Foundation/Foundation.h>
#import <UIKit/UIkit.h>

@protocol OSZViewAdapterProtocol <NSObject>
- (NSString *)setLabelStr;
- (NSString *)setButtonStr;
@end

OSZThreeView.h:(View)

#import <UIKit/UIKit.h>
#import "OSZViewAdapterProtocol.h"
@interface OSZThreeView : UIView
//有适配器给控件赋值,不用暴露属性加载数据了
- (void)loadData:(id<OSZViewAdapterProtocol>)data;
@end

OSZThreeView.m:(View)

#import "OSZThreeView.h"

@interface OSZThreeView ()
//文字
@property (nonatomic, weak) UILabel *lbl;
//按钮
@property (nonatomic, weak) UIButton *btn;
@end

@implementation OSZThreeView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self setupUI];
    }
    return self;
}

//仅仅设置ui
- (void)setupUI
{
    self.backgroundColor = [UIColor grayColor];
    
    CGRect rect = CGRectMake(2,2,100,25);
    UILabel *lbl = [[UILabel alloc]initWithFrame:rect];
    [lbl setBackgroundColor:[UIColor whiteColor]];
    self.lbl = lbl;
    [self addSubview:self.lbl];
    
    rect = CGRectMake(110, 5, 50, 20);
    UIButton *btn = [[UIButton alloc]initWithFrame:rect];
    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [btn setBackgroundColor:[UIColor whiteColor]];
    self.btn = btn;
    [self addSubview:self.btn];
}

//用适配器给控件赋值,达到解耦的效果
-(void)loadData:(id<OSZViewAdapterProtocol>)data
{
    self.lbl.text = [data setLabelStr];
    [self.btn setTitle:[data setButtonStr] forState:UIControlStateNormal];
}

@end

OSZOneModel.h:(Model)

#import <Foundation/Foundation.h>
@interface OSZOneModel : NSObject
@property (nonatomic, copy) NSString *lblOneStr;
@property (nonatomic, copy) NSString *btnOneStr;
@end

OSZTwoModel.h:(Model)

#import <Foundation/Foundation.h>
@interface OSZTwoModel : NSObject
@property (nonatomic, copy) NSString *lblTwoStr;
@property (nonatomic, copy) NSString *btnTwoStr;
@end

作为Model,OSZOneModel.m,OSZTwoModel.m没有东西的

OSZViewAdapter.h:(Adapter)

//基本适配器
#import <Foundation/Foundation.h>
#import "OSZViewAdapterProtocol.h"

@interface OSZViewAdapter : NSObject<OSZViewAdapterProtocol>
//设立属性保存输入的数据
@property (nonatomic, weak) id data;
//保存输入数据
- (instancetype)initWithData:(id)data;
@end

OSZViewAdapter.m:

#import "OSZViewAdapter.h"
@implementation OSZViewAdapter

- (instancetype)initWithData:(id)data
{
    if (self = [super init])
    {
        self.data = data;
    }
    return self;
}
- (NSString *)setLabelStr
{
    return nil;
}
- (NSString *)setButtonStr
{
    return nil;
}
@end

OSZOneModelAdapter.h:(Adapter)

//类适配器
//第一个模型的适配器
#import "OSZViewAdapter.h"
@interface OSZOneModelAdapter : OSZViewAdapter
@end

OSZOneModelAdapter.m:

#import "OSZOneModelAdapter.h"
#import "OSZOneModel.h"
@implementation OSZOneModelAdapter

- (NSString *)setLabelStr
{
    OSZOneModel *model = self.data;
    return model.lblOneStr;
}
- (NSString *)setButtonStr
{
    OSZOneModel *model = self.data;
    return model.btnOneStr;
}
@end

OSZTwoModelAdapter.h:(Adapter)

//类适配器
//第二个模型的适配器
#import "OSZViewAdapter.h"
@interface OSZTwoModelAdapter : OSZViewAdapter
@end

OSZTwoModelAdapter.m:

#import "OSZTwoModelAdapter.h"
#import "OSZTwoModel.h"
@implementation OSZTwoModelAdapter
- (NSString *)setLabelStr
{
    OSZTwoModel *model = self.data;   
    return model.lblTwoStr;
}
- (NSString *)setButtonStr
{
    OSZTwoModel *model = self.data;   
    return model.btnTwoStr;
}
@end

OSZModelAdapter.h:(对象适配器Adapter)

//对象适配器,综合OSZOneModelAdapter与OSZTwoModelAdapter的功能
//使用了if-else
#import "OSZViewAdapter.h"
@interface OSZModelAdapter : OSZViewAdapter
@end

OSZModelAdapter.m:

#import "OSZModelAdapter.h"
#import "OSZOneModel.h"
#import "OSZTwoModel.h"

@implementation OSZModelAdapter

- (NSString *)setLabelStr
{
//    确定一个对象是否是当前类的成员
    if ([self.data isMemberOfClass:[OSZOneModel class]])
    {
        OSZOneModel *model = self.data;
        
        return model.lblOneStr;
    }
    else if ([self.data isMemberOfClass:[OSZTwoModel class]])
    {
        OSZTwoModel *model = self.data;
        
        return model.lblTwoStr;
    }
    else
    {
        return nil;
    }
}

- (NSString *)setButtonStr
{
    if ([self.data isMemberOfClass:[OSZOneModel class]])
    {
        OSZOneModel *model = self.data;
        
        return model.btnOneStr;
    }
    else if ([self.data isMemberOfClass:[OSZTwoModel class]])
    {
        OSZTwoModel *model = self.data;
        
        return model.btnTwoStr;
    }
    else
    {
        return nil;
    }
}

@end

控制器代码:(Controller)

#import "OSZThreeVC.h"

#import "OSZOneModel.h"
#import "OSZTwoModel.h"
#import "OSZThreeView.h"
//类适配器
#import "OSZOneModelAdapter.h"
#import "OSZTwoModelAdapter.h"
//对象适配器
#import "OSZModelAdapter.h"
@interface OSZThreeVC ()
@end

@implementation OSZThreeVC
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
//    [self setupUI1];
    [self setupUI2];
}
//    类适配器
- (void)setupUI1
{
    //第一种数据
    //获取数据,一般是网络请求的成功回调,这里就假数据了
    OSZOneModel *oneModel = [[OSZOneModel alloc]init];
    oneModel.lblOneStr = @"qweqweqwe";
    oneModel.btnOneStr = @"btn1";
    //处理数据
    OSZOneModelAdapter *modelAda1 = [[OSZOneModelAdapter alloc]initWithData:oneModel];
    //创建ui
    OSZThreeView *threeView1 = [[OSZThreeView alloc]initWithFrame:CGRectMake(100, 100, 200, 30)];
    //加载适配器的数据
    [threeView1 loadData:modelAda1];
    [self.view addSubview:threeView1];
    
    
    //第二种数据
    OSZTwoModel *twoModel = [[OSZTwoModel alloc]init];
    twoModel.lblTwoStr = @"asdfadfasdf";
    twoModel.btnTwoStr = @"btn2";
    OSZTwoModelAdapter *modelAda2 = [[OSZTwoModelAdapter alloc]initWithData:twoModel];
    OSZThreeView *threeView2 = [[OSZThreeView alloc]initWithFrame:CGRectMake(80, 180, 250, 30)];
    [threeView2 loadData:modelAda2];
    [self.view addSubview:threeView2];
}

//对象适配器
-(void)setupUI2
{
    //第一种数据
    OSZOneModel *oneModel = [[OSZOneModel alloc]init];
    oneModel.lblOneStr = @"zxcvcvzxcv";
    oneModel.btnOneStr = @"btn1";
    //对象适配器
    OSZModelAdapter *modelAda1 = [[OSZModelAdapter alloc]initWithData:oneModel];
    OSZThreeView *threeView1 = [[OSZThreeView alloc]initWithFrame:CGRectMake(100, 100, 200, 30)];
    [threeView1 loadData:modelAda1];
    [self.view addSubview:threeView1];
    
    //第二种数据
    OSZTwoModel *twoModel = [[OSZTwoModel alloc]init];
    twoModel.lblTwoStr = @"uioujiouio";
    twoModel.btnTwoStr = @"btn2";
    //此处不用更换适配器了
    OSZModelAdapter *modelAda2 = [[OSZModelAdapter alloc]initWithData:twoModel];
    OSZThreeView *threeView2 = [[OSZThreeView alloc]initWithFrame:CGRectMake(80, 180, 250, 30)];
    [threeView2 loadData:modelAda2];
    [self.view addSubview:threeView2];
}
@end

适配器模式的优点是解耦
让视图类不合数据类产生耦合,使View更加独立,有适配器给控件赋值,不用暴露view属性加载数据了

缺点是会新增加很多类,
最少三个文件,一个protocol,一套对象适配器的.h,.m,使项目文件更多,代码可读性更弱了
所以酌情使用吧


2 桥接模式

实现层次结构定义了供抽象层次使用的底层接口
实现类的引用被封装于抽象层的实例中时形成了桥接

一个遥控器随意切换遥控两个机器人的例子:
(OSZ为oldSixZhu缩写)获取源码

ConsoleCommands.h(没啥意义,就是个枚举,定义方向):

typedef enum{
    up,
    down,
    left,
    right
} ConsoleCommand;

OSZRobot.h(机器人基类):

#import <Foundation/Foundation.h>
#import "ConsoleCommands.h"
@interface OSZRobot : NSObject
//根据命令加载指令到数据结构(机器人)
- (void)loadInstructionsForCommand:(ConsoleCommand)command;
//执行指令
- (void)executeInstructions;

//其他方法
@end

OSZRobot.m:

#import "OSZRobot.h"
@implementation OSZRobot
- (void)loadInstructionsForCommand:(ConsoleCommand)command
{
    NSLog(@"OSZRobot 加载指令");
}
- (void)executeInstructions
{
    NSLog(@"OSZRobot 执行指令");
}
@end

OSZRobot1.h(第一种机器人):

#import "OSZRobot.h"
@interface OSZRobot1 : OSZRobot
//重载父类方法
//其他特有的方法
@end

OSZRobot1.m:

#import "OSZRobot1.h"
@implementation OSZRobot1
- (void)loadInstructionsForCommand:(ConsoleCommand)command
{
    NSLog(@"OSZRobot1 加载指令--%d",command);
}
- (void)executeInstructions
{
    NSLog(@"OSZRobot1 执行指令");
}
@end

OSZRobot2.h(第二种机器人):

#import "OSZRobot.h"
@interface OSZRobot2 : OSZRobot
//重载父类方法
//其他特有的方法
@end

OSZRobot2.m:

#import "OSZRobot2.h"
@implementation OSZRobot2
- (void)loadInstructionsForCommand:(ConsoleCommand)command
{
    NSLog(@"OSZRobot2 加载指令--%d",command);
}
- (void)executeInstructions
{
    NSLog(@"OSZRobot2 执行指令");
}
@end

OSZConsole.h(控制器,控制机器人):

#import <Foundation/Foundation.h>
#import "ConsoleCommands.h"
#import "OSZRobot.h"
@interface OSZConsole : NSObject
@property (nonatomic, strong) OSZRobot *robot;
//OSZConsole代表对OSZRobot实现的一种抽象
//OSZConsole就是抽象类,OSZRobot就是实现类
//抽象类层次结构的变化不会影响实现类层次结构的变化
//就是所谓的"从实现中把抽象分离出来而又要让它们联系在一起"

//只是命令机器人调用方法,并不是具体的控制器
//目的是完成控制器与机器人的桥接
- (void)sendCommand:(ConsoleCommand)command;
@end

OSZConsole.m:

#import "OSZConsole.h"
@implementation OSZConsole
- (void)sendCommand:(ConsoleCommand)command
{
    [self.robot loadInstructionsForCommand:command];
    [self.robot executeInstructions];
}
@end

OSZRealConsole.h(控制器的子类,具体实现):

#import "OSZConsole.h"
@interface OSZRealConsole : OSZConsole
- (void)up;
- (void)down;
- (void)left;
- (void)right;
@end

OSZRealConsole.m:

#import "OSZRealConsole.h"
#import "ConsoleCommands.h"
@implementation OSZRealConsole
//当我们发送指令的时候,由父类来统一实现,达到整合与复用,避免各子类混淆
//并由父类来根据机器人种类处理合适的指令
//我们可以创造多个子类,发出特定的功能指令
- (void)up
{
    [super sendCommand:up];
}
- (void)down
{
    [super sendCommand:down];
}
- (void)left
{
    [super sendCommand:left];
}
- (void)right
{
    [super sendCommand:right];
}
@end

控制器OSZFourVC.m代码:

#import "OSZFourVC.h"
//两种机器人(电视机)
#import "OSZRobot1.h"
#import "OSZRobot2.h"
//控制器(遥控器)
#import "OSZRealConsole.h"
@interface OSZFourVC ()
@end

@implementation OSZFourVC
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    //我想要一个遥控器能遥控两种机器人,而不是换遥控器
    //创建两个机器人
    OSZRobot1 *robot1 = [[OSZRobot1 alloc]init];
    OSZRobot2 *robot2 = [[OSZRobot2 alloc]init];
    
    OSZRealConsole *console = [[OSZRealConsole alloc]init];
    console.robot = robot1;
    [console up];
    //OSZRobot1 加载指令--0
    //OSZRobot1 执行指令
    
    console.robot = robot2;
    [console up];
    [console left];
    //OSZRobot2 加载指令--0
    //OSZRobot2 执行指令
    //OSZRobot2 加载指令--2
    //OSZRobot2 执行指令
}
@end

桥接模式本质是"分离抽象和实现",而且是用对象组合的方式,而不是继承的方式来实现,达到了解耦,
使抽象类和实现类可以各自扩展变化,提高了扩展性

缺点则仍然是设计模式的通病,增加了系统的理解与设计难度,代码可读性弱,
需要我们进行抽象设计与编程,要求更高了


3.外观模式

为子系统的一组接口提供简化的接口,即用一层整合多个有关系的层,使在C层方法调用更简单

一个打出租的例子:
(OSZ为oldSixZhu缩写)获取源码
OSZCar.h(出租车):

#import <Foundation/Foundation.h>
@interface OSZCar : NSObject
//点火
- (void)fire;
//换挡
- (void)changeGears;
//刹车
- (void)brakes;
@end

OSZCar.m:

#import "OSZCar.h"
@implementation OSZCar
- (void)fire
{
    NSLog(@"点火");
}
- (void)changeGears
{
    NSLog(@"换挡");
}
- (void)brakes
{
    NSLog(@"刹车");
}
@end

OSZTaximeter.h(出租车计价器):

#import <Foundation/Foundation.h>
@interface OSZTaximeter : NSObject
- (void)start;
- (void)stop;
@end

OSZTaximeter.m:

#import "OSZTaximeter.h"
@implementation OSZTaximeter
- (void)start
{
    NSLog(@"开始计价");
}
- (void)stop
{
    NSLog(@"停止计价");
}
@end

OSZCabDriver.h(出租车司机作为"外观"):

#import <Foundation/Foundation.h>
#import "OSZCar.h"
#import "OSZTaximeter.h"
@interface OSZCabDriver : NSObject
//目的地
- (void)driveToLocation:(CGPoint)x;
@end

OSZCabDriver.m:

#import "OSZCabDriver.h"
@implementation OSZCabDriver
- (void)driveToLocation:(CGPoint)x
{
    //启动计价器
    OSZTaximeter *meter = [[OSZTaximeter alloc]init];
    [meter start];
    //操作车辆到达指定位置
    OSZCar *car = [[OSZCar alloc]init];
    [car fire];
    [car changeGears];
    [car changeGears];
    //到达位置,停车
    NSLog(@"到达%@", NSStringFromCGPoint(x));
    [car brakes];
    //停止计价器
    [meter stop];
}
@end

控制器OSZFiveVC.m:

#import "OSZFiveVC.h"
#import "OSZCabDriver.h"
@interface OSZFiveVC ()
@end

@implementation OSZFiveVC
- (void)viewDidLoad {
    [super viewDidLoad]; 
    //我叫了个出租车,告诉出租车司机目的地即可
    OSZCabDriver *driver = [[OSZCabDriver alloc]init];
    [driver driveToLocation:CGPointMake(100, 100)];
//    开始计价
//    点火
//    换挡
//    换挡
//    到达{100, 100}
//    刹车
//    停止计价
}
@end

外观模式的应用还是挺简单挺广泛的,几乎处处可见

下一节iOS设计模式三(中介者)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 我的笔记本电脑的工作电压是20V,而我国的家庭用电是220V,如何让20V的笔记本电脑能够在220V的电压下工作?...
    justCode_阅读 1,410评论 0 5
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,057评论 25 707
  • 前言:设计模式之结构型模式软件模式与具体的应用领域无关,也就是说无论你从事的是移动应用开发、桌面应用开发、Web ...
    markfork阅读 2,424评论 4 13
  • 本篇文章介绍一种设计模式——命令模式。本篇文章内容参考《JAVA与模式》之适配器模式,Android设计模式源码解...
    Ruheng阅读 1,857评论 0 3
  • 城市的早晨,喧嚣而混乱,充满了戾气。路上挤满了各种汽车,充满了各种学生。上班的大人和送孩子上学的家长,急切的神情溢...
    一声笑阅读 254评论 0 0