承接上文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
外观模式的应用还是挺简单挺广泛的,几乎处处可见