最近在学习《Objective-C编程之道:iOS设计模式解析》,本文是对桥接模式的一个分析和例子实现。
例子地址:Bryanthelol/iOS_DesignPattern
里面包含书的例子和我自己实现的例子。
标签:接口适配
一、桥接模式是什么
桥接模式的目的是把抽象层次结构从其实现中分离出来,使其能够独立变更。
抽象层定义了供客户端使用的上层的抽象接口
实现层次结构定义了供抽象层次使用的底层接口
实现类的引用被封装于抽象层的实例中时
桥接就形成了
这样的解释肯定还是让人看不懂。用白话来说就是:
- 存在两个Base类,这两个类分别代表:抽象的Base类和实现的Base类
- Abstraction Base Class
- Implementation Base Class
- 抽象Base类有很多不同的子类
- 实现Base类同样有很多不同的子类
- 抽象Base类持有实现Base类的一个实例
- 然后这个抽象Base类调用自身的方法,这个方法会调用其持有的实现Base类的实例方法(在使用时,实现Base类的实例被赋值了一个初始化了的实现子类)
这样,想添加新的实现子类,只需要创建一个继承自实现Base类的子类,重写其实现Base类的方法(这个方法就是上面抽象Base类会调用到的方法)。
这对抽象Base类不会有任何影响,并且如果想修改抽象Base类,或者创建更多的抽象子类,也不会影响实现Base类及其子类。
文字看起来还是挺绕,直接上图:
二、桥接模式适用范围:
- 不想在抽象类与其实现类之间形成固定的绑定关系,可以再运行的时候切换
- 抽象类和实现类都可以通过子类继承达到扩展
- 抽象类不能影响调用者的代码
- 抽象类有很多类型的子类或者实现类同样也有很多类型的子类
三、用代码讲解例子
步骤一:
首先,我们有一个抽象类CarBaseClass,代表车这个类型:
CarBaseClass.h
CarBaseClass.m
复制代码
还有一个实现类DrivingCarBaseClass, 代表开车这样一种操作:
DrivingCarBaseClass.h
DrivingCarBaseClass.m
复制代码
步骤二:
然后到了桥接模式的关键一步:
- 让CarBaseClass抽象类持有DrivingCarBaseClass实现类的实例,这便完成了两个BaseClass最关键的桥接行为
CarBaseClass.h
@class DrivingCarBaseClass;
@interface CarBaseClass : NSObject {
@private
DrivingCarBaseClass *_drivingCar;
}
@property(nonatomic, strong) DrivingCarBaseClass *drivingCar;
复制代码
步骤三:
然后根据具体的情况,定义需要桥接的方法。在这里,实现类DrivingCarBaseClass有一个开车的动作,参数为坐车的人数:
DrivingCarBaseClass.h
@interface DrivingCarBaseClass : NSObject
- (void)drive:(NSUInteger)NumOfPerson;
@end
复制代码
这里需要注意的点——实现的Base类只需定义接口,具体的实现则交给继承的子类,比如DrivingSportsCarClass(驾驶跑车类,从DrivingCarBaseClass继承):
DrivingSportsCarClass.m
@implementation DrivingSportsCarClass
// 重载
- (void)drive:(NSUInteger)NumOfPerson {
// do something...
}
@end
复制代码
步骤四:
这时我们回到抽象类CarBaseClass,现在需要把调用实现类drive方法的桥接行为包装起来。
CarBaseClass.h
@class DrivingCarBaseClass;
@interface CarBaseClass : NSObject {
@private
DrivingCarBaseClass *_drivingCar;
}
@property(nonatomic, strong) DrivingCarBaseClass *drivingCar;
// 新添加的
- (void)setNumOfPersonInCar:(NSUInteger)num;
复制代码
CarBaseClass.m
#import "CarBaseClass.h"
#import "DrivingCarBaseClass.h"
@implementation CarBaseClass
@synthesize drivingCar = _drivingCar;
- (void)setNumOfPersonInCar:(NSUInteger)num {
[_drivingCar drive:num];
}
@end
复制代码
步骤四完成的是概念图里的这里:
步骤五:
根据具体需要,创建抽象类CarBaseClass的子类,比如跑车类SportsCarClass。
抽象类负责定义方法的接口,跑车类这个子类则负责实现方法。
比如,我们有一个“与女孩兜风”的方法goForDriveWithGirl。
现在抽象类CarBaseClass里定义:
CarBaseClass.h
@class DrivingCarBaseClass;
@interface CarBaseClass : NSObject {
@private
DrivingCarBaseClass *_drivingCar;
}
@property(nonatomic, strong) DrivingCarBaseClass *drivingCar;
- (void)setNumOfPersonInCar:(NSUInteger)num;
// 新添加的
- (void)goForDriveWithGirl;
复制代码
然后在抽象子类SportsCarClass里实现:
SportsCarClass.m
@implementation SportsCarClass
- (void)goForDriveWithGirl {
[super setNumOfPersonInCar:2];
}
@end
复制代码
这里的关键则是调用的父类的桥接方法,从而达到抽象子类和实现子类之间的沟通。
四、总结
首先,桥接模式的好处是通过对象组合实现继承达不到的事情。
引用《Objective-C编程之道:iOS设计模式解析》一书的话(略作修改):
通过桥接模式,可以看到对象组合的力量。我们为实现Base类搭建的桥接不可能通过直接继承达到。这也是优先使用对象组合而不是继承的一个原因。
其次,桥接模式是把一个接口适配到不同接口的一种方式。
如果我们苦于“如何从实现中把抽象分离出来而又要让它们联系在一起”的时候,就用桥接模式。