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

简书链接:http://www.jianshu.com/p/602407ed19a0

前言

本文主要以代码形式实现每一种设计模式,算是自己的一种复习和实践。相应的代码,也会放到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.[设计模式学习笔记十四:适配器模式、桥接模式与外观模式](http://www.cnblogs.com/peida/archive/2008/08/01/1257574.html)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 模式适配器模式都是结构型设计模式,它们的目的都是解决两个不兼容的口之间的问题,但它们的解决方式有所不同。 相同点: 1. 都是为了解决两个不兼容的口之间的问题。 2. 都采用了对象组合的方式。 不同点: 1. 模式是在不同的抽象层次上进行解耦,而适配器模式是在相同的抽象层次上进行解耦。 2. 模式将抽象化和实现化解耦,使得它们可以独立变化,而适配器模式则是将原本不兼容的口转换成兼容的口,让它们可以一起工作。 3. 模式中,抽象化和实现化可以分别扩展而互不影响,而适配器模式中,适配器是在实现原有口的基础上添加了新的口,两者存在一定的耦合性。 总之,模式适配器模式都是用来解决口不兼容的问题,但是它们的实现方式和应用场景略有不同,需要根据具体情况选择使用哪种模式。 ### 回答2: 模式适配器模式是两种软件设计模式,它们具有一些相似之处,也存在一些不同之处。 1. 相同点: - 目的相似:模式适配器模式都是用于解决不同口之间的兼容性问题,使得不同的类或对象能够协同工作。 - 都通过组合关系实现:模式适配器模式都是通过将一个口与另一个口进行组合,以实现兼容性和协同工作。 2. 不同点: - 使用场景不同:模式主要用于解耦抽象部分和实现部分,使它们可以独立变化;而适配器模式则用于将一个类的口转换成客户端所期望的口,使得原本不兼容的口能够协同工作。 - 目标对象不同:模式的目标是将抽象和实现解耦,让它们可以独立变化;而适配器模式的目标是使得原本不兼容的口能够协同工作,提供一种中间转换层。 - 引起变化的原因不同:模式的变化主要来自于抽象和实现之间的变化,两者可以独立地进行扩展;而适配器模式的变化主要来自于客户端对口的期望变化,需要进行口的适配转换。 总结来说,模式适配器模式都是用于解决口的兼容性问题,但应用场景和目标对象有所不同。模式主要用于解决抽象和实现的耦合问题,适配器模式主要用于对口进行转换,使得原本不兼容的口能够协同工作。 ### 回答3: 模式适配器模式都是常用的软件设计模式,用于处理不兼容的程序组件之间的交互。它们的异同如下: 相同点: 1. 目标:两种模式都用于实现不同组件之间的通信,并且不改变这些组件的源码。 2. 解决方案:两种模式都通过创建一个中间层来解决组件之间的不兼容性问题。 3. 实现方式:两种模式都使用了对象间的关联关系来实现。 不同点: 1. 目的不同:模式的目的是将抽象与实现相分离,使得它们可以独立地变化。适配器模式的目的是将一个类的口转换为客户端所期望的另一个口。 2. 设计原则:模式遵循了开闭原则,通过将抽象部分和具体部分分离,使得它们可以独立地扩展。适配器模式尊重单一职责原则,通过适配器类将不相关的类进行适配,保持职责的单一性。 3. 使用场景:模式主要用于系统可扩展性的设计,能够方便地增加新的抽象和实现。适配器模式主要用于现有系统间的兼容性问题,能够使得不兼容的类可以协同工作。 4. 结构不同:模式将抽象部分与具体实现分离,抽象部分持有一个实现部分的引用,并委托给实现部分完成实际工作。适配器模式通过适配器类将被适配者包装起来,提供客户端期望的口。 综上所述,模式适配器模式有相似之处,例如解决不兼容的组件之间的交互问题,但也有明显的区别,例如目的不同、设计原则不同、使用场景不同和结构不同等。在实际应用中,根据具体的需求,选择适合的模式能够更好地解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值