设计模式——适配器,桥接,外观

前言

本文csdn地址:http://blog.csdn.net/game3108/article/details/51174787
本文主要以代码形式实现每一种设计模式,算是自己的一种复习和实践。相应的代码,也会放到github上。
本文的类图均来自于《Objective-C编程之道 iOS设计模式解析》。

本篇主要讲:

  • 适配器
  • 桥接
  • 外观

6.适配器

概念:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。

适配器主要有两种实现方式:

  • 类适配器
    通过继承来适配两个接口。
  • 对象适配器
    组合一个适配器对象的引用。

类图:

Paste_Image.png
Paste_Image.png

何时使用:

  • 已有类的接口与需求不匹配。
  • 想要一个可复用的类,该类能够同可能带有不兼容接口的其他类协作。
  • 需要适配一个类的几个不同自雷,可是让每一个子类去子类化一个类适配器又不现实,那么可以使用对象适配器(也叫委托)来适配其父类的接口。

类适配器的例子:

EATarget对象

#import <Foundation/Foundation.h>

@protocol EATarget <NSObject>
- (void) request;
@end

EAAdaptee对象:

#import <Foundation/Foundation.h>

@interface EAAdaptee : NSObject
- (void) specificRequest;
@end

#import "EAAdaptee.h"

@implementation EAAdaptee
- (void) specificRequest{
}
@end

EAAdapter对象:

#import "EAAdaptee.h"
#import "EATarget.h"

@interface EAAdapter : EAAdaptee<EATarget>

@end

#import "EAAdapter.h"

@implementation EAAdapter

- (void) request{
    [super specificRequest];
    //to do something
    //xxxxxx
}

@end

对象适配器的例子:

delegate(委托)就是一个典型的对象适配器的用法。
UITableView,通过delegate回调didSelectRowAtIndexPath操作其他对象。其中UITableView为client,UITableViewDelegate为target

OASelectObject Adaptee:

#import <Foundation/Foundation.h>

@interface OASelectObject : NSObject
- (void) didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
@end

#import "OASelectObject.h"

@implementation OASelectObject
- (void) didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
}
@end

OAUIViewController adapter对象

#import <UIKit/UIKit.h>

@interface OAUIViewController : UIViewController

@end

#import "OAUIViewController.h"
#import "OASelectObject.h"

@interface OAUIViewController ()<UITableViewDelegate,UITableViewDataSource>{
    OASelectObject *_selectObject;
}

@end

@implementation OAUIViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
    _selectObject = [[OASelectObject alloc]init];
    
    UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
    tableView.backgroundColor = [UIColor blackColor];
    tableView.delegate = self;
    tableView.dataSource = self;
    [self.view addSubview:tableView];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    NSString *cellIdentifier = @"cell_identifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if ( !cell ){
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
        cell.backgroundColor = [UIColor grayColor];
    }
    
    return cell;
}

#pragma mark UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [_selectObject didSelectRowAtIndexPath:indexPath];
}

@end

7.桥接

概念:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

类图:

Paste_Image.png

何时使用:

  • 不想在抽象与其实现之间形成固定的绑定关系(这样就能在运行时切换实现)。
  • 抽象及其实现都应可以通过子类化独立进行扩展。
  • 对抽象的实现进行修改不应影响客户端代码。
  • 如果每个实现需要额外的子类以细化抽象,则说明有必要把它们分为两个部分。
  • 想在带有不同抽象接口的多个对象之间共享一个实现。

代码场景:
电视遥控器会根据不同电视机改变它的实现,而且遥控器本身也会改变。所以抽象出电视和遥控器两个抽象类出来。

电视类:

#import <Foundation/Foundation.h>

@interface TV : NSObject
- (void)on;
- (void)off;
- (void)tuneChannel:(NSInteger)channel;
@end

#import "TV.h"

@interface TV(){
    NSInteger _nowChannel;
    BOOL _onShow;
}

@end

@implementation TV

- (void)on{
    _onShow = NO;
}
- (void)off{
    _onShow = YES;
}
- (void)tuneChannel:(NSInteger)channel{
    _nowChannel = channel;
}

@end

电视子类:

#import "TV.h"

@interface RCA : TV

@end

#import "RCA.h"

@implementation RCA
- (void)tuneChannel:(NSInteger)channel{
    NSLog(@"RCA tunechannel");
    [super tuneChannel:channel];
}
@end
#import "TV.h"

@interface Sony : TV

@end

#import "Sony.h"

@implementation Sony
- (void)tuneChannel:(NSInteger)channel{
    NSLog(@"Sony tunechannel");
    [super tuneChannel:channel];
}
@end

遥控类:

#import <Foundation/Foundation.h>
#import "TV.h"

@interface RemoveControl : NSObject
@property (nonatomic, strong) TV *implementor;
- (void) on;
- (void) off;
- (void) setChannel:(NSInteger)channel;
@end

#import "RemoveControl.h"

@implementation RemoveControl
- (void) on{
    [_implementor on];
}
- (void) off{
    [_implementor off];
}
- (void) setChannel:(NSInteger)channel{
    [_implementor tuneChannel:channel];
}
@end

遥控子类:

#import "RemoveControl.h"

@interface ConcreteRemote : RemoveControl
- (void) setStation:(NSInteger)station;
- (void) nextChannel;
- (void) previousChannel;
@end

#import "ConcreteRemote.h"

@interface ConcreteRemote(){
    NSInteger _currentStation;
}

@end

@implementation ConcreteRemote
- (void) setStation:(NSInteger)station{
    _currentStation = station;
    [super setChannel:station];
}
- (void) nextChannel{
    [super setChannel:_currentStation + 1];
}
- (void) previousChannel{
    [super setChannel:_currentStation - 1];
}
@end

8.外观

概念:为系统中的一组接口提供一个统一的接口。外观定义一个高层接口,让子系统更易于使用。

结构图:

Paste_Image.png

何时使用:

  • 子系统正逐渐变得复杂。应用模式的过程中演化出许多类。可以使用外观为这些子系统类提供一个较简单的接口。
  • 可以使用外观对子系统进行分层。每个子系统级别有一个外观作为入口点。让它们通过其外观进行通信,可以简化他们的依赖关系。

代码场景:
家庭影院看电影的时候,可能要先放下屏幕,关灯,然后播放dvd等。使用外观可以用一个家庭影院外观类进行统一管理。

家庭外观类:

#import <Foundation/Foundation.h>
#import "DvdPlayer.h"
#import "CdPlayer.h"
#import "Screen.h"
#import "TheaterLights.h"

@interface HomeTheaterFacade : NSObject
@property (nonatomic, strong) DvdPlayer *dvd;
@property (nonatomic, strong) CdPlayer *cd;
@property (nonatomic, strong) Screen *screen;
@property (nonatomic, strong) TheaterLights *lights;
- (void) watchMovie:(NSString*) movie;
- (void) endMovie;
@end

#import "HomeTheaterFacade.h"

@implementation HomeTheaterFacade

- (void) watchMovie:(NSString*) movie{
    NSLog(@"get ready to watch a movie");
    [_lights off];
    [_screen down];
    [_dvd on];
    [_dvd play:movie];
    
}
- (void) endMovie{
    NSLog(@"shutting movie theater down");
    [_lights on];
    [_screen up];
    [_dvd stop];
    [_dvd eject];
    [_dvd off];
}

@end

总结:

1.适配器,桥接,外观的使用时机?

  • 适配器:用于设计完成之后,主要适用于解决两个已有接口的匹配,而接口本身是一个黑匣子,你无法去修改接口的实现。
  • 桥接模式:用于设计的初期,参与接口的类是稳定的,用户可以修改扩展和修改接口的类,但不能改变接口,通过接口继承实现或者类继承实现功能扩展。
  • 外观模式:用于设计的初期,为一组子接口提供统一接口。相对于适配器的小粒度功能继承,更像一个大粒度的适配器,当封装系统演化的时候,需要新的外观对象,而这个对象起到了适配器的作用。

参考资料

1.《Objective-C编程之道 iOS设计模式解析》
2.《Head First设计模式》
3.设计模式学习笔记十四:适配器模式、桥接模式与外观模式

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

推荐阅读更多精彩内容