读《大话设计模式》二

结构型模式

适配器模式

模式动机

适配器提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。这就是适配器模式的模式动机。

模式定义

适配器模式:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

模式结构

适配器模式包含如下角色:

  • HCDPlayer:目标抽象类
  • HCDTranslator:适配器类
  • HCDForeignCenter:适配者类
    适配器模式类图
时序图
适配器模式时序图
源码
//调用方式
    HCDPlayer *forward = [[HCDForwards alloc] initWithName:@"maidi"];
    [forward attack];
    [forward defense];
    
    HCDForeignCenter *foreignCenter = [[HCDForeignCenter alloc] initWithName:@"姚明"];
    HCDPlayer *translator = [[HCDTranslator alloc] initWithForeigncenter:foreignCenter];
    [translator attack];
    [translator defense];
//HCDPlayer.h
@interface HCDPlayer : NSObject

@property (nonatomic,copy) NSString *name;

-(void)attack;

-(void)defense;

-(instancetype)initWithName:(NSString *)name;

@end

//HCDForwards.m
@implementation HCDForwards

-(void)attack{
    NSLog(@"前锋%@进攻",self.name);
}

-(void)defense{
    NSLog(@"前锋%@防守",self.name);
}

@end

//HCDTranslator.m
@interface HCDTranslator ()

@property(nonatomic, strong) HCDForeignCenter *foreigncenter;

@end

@implementation HCDTranslator

-(instancetype)initWithForeigncenter:(HCDForeignCenter *)foreigncenter {
    self = [super init];
    if (self) {
        _foreigncenter = foreigncenter;
    }
    return self;
} 

-(void)defense{
    [self.foreigncenter foreignDefent];
}

-(void)attack{
    [self.foreigncenter foreignAttact];
}

@end
//HCDForeignCenter.m
@implementation HCDForeignCenter

- (instancetype)initWithName:(NSString *)name{
    self = [super init];
    if (self) {
        _name = name;
    }
    return self;
}

- (void)foreignAttact{
    NSLog(@"外籍中锋%@进攻",self.name);
}

- (void)foreignDefent{
    NSLog(@"外籍中锋%@防守",self.name);
}

@end

桥接模式

模式动机

如果需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Linux、Unix等)上播放多种格式的视频文件,常见的视频格式包括MPEG、RMVB、AVI、WMV等。现使用桥接模式设计该播放器。此时至少有如下两种设计方案:

  • 第一种设计方案是为每一种操作系统都提供一套支持各种视频格式的版本;
  • 第二种设计方案是根据实际需要对操作系统和支持的视频格式进行组合。

对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
尽量使用组合,而不要使用继承。

模式定义

桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式。

模式结构

桥接模式包含如下角色:

  • Abstraction:抽象类
  • RefinedAbstraction:扩充抽象类
  • Implementor:实现类接口
  • ConcreteImplementor:具体实现类


    桥接模式类图
时序图
桥接模式时序图
源码

装饰模式

模式动机

一般有两种方式可以实现给一个类或对象增加行为:

  • 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机;
  • 关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)。

装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

模式定义

装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。它是一种对象结构型模式。

模式结构

装饰模式包含如下角色:

  • Component: 抽象构件
  • ConcreteComponent: 具体构件
  • Decorator: 抽象装饰类
  • ConcreteDecorator: 具体装饰类


    装饰模式类图
时序图
装饰模式时序图
源码
//使用示例
    LTPerson *xc = [[LTPerson alloc] initWithName:@"小菜"];
    
    NSLog(@"\n第一种装扮");
    LTSneakers *sneaker = [[LTSneakers alloc] init];
    LTBigTrouser *bigTrouser = [[LTBigTrouser alloc] init];
    LTTshirts *tshirts = [[LTTshirts alloc] init];
    
    [sneaker decorate:xc];
    [bigTrouser decorate:sneaker];
    [tshirts decorate:bigTrouser];
    [tshirts show];
    
    NSLog(@"\n第二种装扮");
    LTLeatherShoes *leatherShoes = [[LTLeatherShoes alloc] init];
    LTTie *tie = [[LTTie alloc] init];
    LTSuit *suit = [[LTSuit alloc] init];
    
    [leatherShoes decorate:xc];
    [tie decorate:leatherShoes];
    [suit decorate:tie];
    [suit show];
//LTPerson.h
@interface LTPerson : NSObject

- (instancetype)initWithName:(NSString *)name;

- (void)show;

@end

//LTPerson.m
@interface LTPerson ()

@property (nonatomic, copy) NSString *name;

@end

@implementation LTPerson

- (instancetype)initWithName:(NSString *)name {
    self = [super init];
    if (self) {
        _name = name;
    }
    return self;
}

- (void)show {
    NSLog(@"装扮的%@",self.name);
}

@end
//LTFinery.h
@interface LTFinery : LTPerson

- (void)decorate:(LTPerson *)person;

@end

@interface LTTshirts : LTFinery

@end

@interface LTBigTrouser : LTFinery

@end

@interface LTSneakers : LTFinery

@end

@interface LTLeatherShoes : LTFinery

@end

@interface LTTie : LTFinery

@end

@interface LTSuit : LTFinery

@end
//LTFinery.m
@interface LTFinery ()

@property (nonatomic, strong) LTPerson *person;

@end

@implementation LTFinery

- (void)decorate:(LTPerson *)person {
    self.person = person;
}

- (void)show {
    if(self.person) {
        [self.person show];
    }
}

@end

@implementation LTTshirts

- (void)show {
    NSLog(@"大T恤");
    [super show];
}

@end

@implementation LTBigTrouser

- (void)show {
    NSLog(@"垮裤");
    [super show];
}

@end

@implementation LTSneakers

- (void)show {
    NSLog(@"破球鞋");
    [super show];
}

@end

@implementation LTLeatherShoes

- (void)show {
    NSLog(@"皮鞋");
    [super show];
}

@end

@implementation LTTie

- (void)show {
    NSLog(@"领带");
    [super show];
}

@end

@implementation LTSuit

- (void)show {
    NSLog(@"西装");
    [super show];
}

@end

外观模式

模式动机

为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。

模式定义

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。它是一种对象结构型模式。

模式结构

外观模式包含如下角色:

  • Facade: 外观角色
  • SubSystem:子系统角色
外观模式类图
时序图
外观模式时序图
源码
//使用示例
    HCDFound *found = [[HCDFound alloc]init];
    [found buyFund];
    [found sellFund];
//HCDstock.h
@interface HCDstock : NSObject<HCDStockProtocol>

@end
@interface HCDFound()

@property (nonatomic, strong) HCDstock1 *stock1;
@property (nonatomic, strong) HCDstock2 *stock2;
@property (nonatomic, strong) HCDstock3 *stock3;

@end

@implementation HCDFound

-(instancetype)init{
    self = [super init];
    if (self) {
        _stock1 = [[HCDstock1 alloc]init];
        _stock2 = [[HCDstock2 alloc]init];
        _stock3 = [[HCDstock3 alloc]init];
    }
    return self;
}

-(void)buyFund{
    [self.stock1 buy];
    [self.stock2 buy];
    [self.stock3 buy];
}

-(void)sellFund{
    [self.stock1 sell];
    [self.stock2 sell];
    [self.stock3 sell];
}

享元模式

模式动机

面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。

  • 享元模式正是为解决这一类问题而诞生的。享元模式通过共享技术实现相同或相似对象的重用。
  • 在享元模式中可以共享的相同内容称为内部状态(IntrinsicState),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的。
  • 在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。
  • 在享元模式中共享的是享元对象的内部状态,外部状态需要通过环境来设置。在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象。享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。
模式定义

享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

模式结构

享元模式包含如下角色:

  • Flyweight: 抽象享元类
  • ConcreteFlyweight: 具体享元类
  • UnsharedConcreteFlyweight: 非共享具体享元类
  • FlyweightFactory: 享元工厂类


    享元模式类图
时序图
享元模式时序图
源码
    //使用示例
    HCDWebSiteFactory *facoty = [[HCDWebSiteFactory alloc]init];
    HCDWebSiteType fx = [facoty getWebSiteCategory:@"产品展示"];
    HCDUser *user = [[HCDUser alloc]init];
    user.name = @"小菜";
    [fx use:user];
    
    HCDWebSiteType fy = [facoty getWebSiteCategory:@"产品展示"];
    HCDUser *user1 = [[HCDUser alloc]init];
    user1.name = @"大鸟";
    [fy use:user1];
    
    HCDWebSiteType fz = [facoty getWebSiteCategory:@"博客"];
    HCDUser *user2 = [[HCDUser alloc]init];
    user2.name = @"咪咪";
    [fz use:user2];
//HCDWebSiteFactory.h
@interface HCDWebSiteFactory : NSObject

@property(nonatomic,strong) NSDictionary *flyweights;

-(id<HCDWebSite> )getWebSiteCategory:(NSString *)webkey;

-(NSInteger)getWebSiteCount;

@end
//HCDWebSiteFactory.m
@implementation HCDWebSiteFactory

-(instancetype)init{
    self = [super init];
    if (self) {
        _flyweights = [NSDictionary dictionary];
    }
    return self;
}

-(id<HCDWebSite> )getWebSiteCategory:(NSString *)webkey{
    __block id<HCDWebSite> webset = nil;
    [self.flyweights enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        if (webkey == key) {
            webset = obj;
            *stop = YES;
        }
    }];
    if (webset == nil) {
        HCDConcreteWebSite  *concreteset = [[HCDConcreteWebSite alloc] init];
        concreteset.webName = webkey;
        webset = concreteset;
        
        NSMutableDictionary *mutabledic = [NSMutableDictionary dictionaryWithDictionary:self.flyweights];
        [mutabledic setObject:webset forKey:webkey];
        self.flyweights = [NSDictionary dictionaryWithDictionary:mutabledic];
    }
    return webset;
}

-(NSInteger)getWebSiteCount{
    return self.flyweights.count;
}

@end
//HCDConcreteWebSite.h
@interface HCDConcreteWebSite : NSObject<HCDWebSite>

@property(nonatomic,strong)NSString *webName;

@end

//HCDConcreteWebSite.m
@implementation HCDConcreteWebSite

-(void)use:(HCDUser *)user{
    NSLog(@"网站分类:%@,用户:%@",self.webName,user.name);
}

@end

代理模式

模式动机

在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

模式定义

在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。

模式结构

代理模式包含如下角色:

  • Subject: 抽象主题角色
  • Proxy: 代理主题角色
  • RealSubject: 真实主题角色


    代理模式类图
时序图
代理模式时序图
源码
//使用示例
    HCDschoolGirl *girl = [[HCDschoolGirl alloc] init];
    girl.name = @"哈哈哈哈哈";
    HCDproxy *proxy = [[HCDproxy alloc] initWithSchoolGirl:girl];
    [proxy giveFlowers];
    [proxy giveDolls];
    [proxy giveChocolate]; 
//HCDschoolGirl.h
@interface HCDschoolGirl : NSObject

@property(nonatomic,strong)NSString *name;

@end

//HCDgiveGift.h
@protocol HCDgiveGift <NSObject>
///  送洋娃娃
- (void)giveDolls;

///  送鲜花
- (void)giveFlowers;

///  送巧克力
- (void)giveChocolate;
@end

//HCDpursuit.m
@interface HCDpursuit ()

@property(nonatomic,strong)HCDschoolGirl *schoolGirl;

@end

@implementation HCDpursuit
-(instancetype)initWithSchoolGirl:(HCDschoolGirl *)schoolGirl{
    self = [super init];
    if (self) {
        _schoolGirl = schoolGirl;
    }
    return self;
}
-(void)giveChocolate{
    NSLog(@"送你巧克力%@",self.schoolGirl.name);
}
-(void)giveDolls{
    NSLog(@"送你洋娃娃%@",self.schoolGirl.name);
}
-(void)giveFlowers{
    NSLog(@"送你玫瑰花%@",self.schoolGirl.name);
}
@end

//HCDproxy.m
@interface HCDproxy ()

@property (strong, nonatomic) HCDpursuit *pursuit;

@end

@implementation HCDproxy

- (instancetype)initWithSchoolGirl:(HCDschoolGirl *)schoolGirl {
    self = [super init];
    if (self) {
        self.pursuit = [[HCDpursuit alloc] initWithSchoolGirl:schoolGirl];
    }
    return self;
}

- (void)giveDolls {
    [self.pursuit giveDolls];
}

- (void)giveFlowers {
    [self.pursuit giveFlowers];
}

- (void)giveChocolate {
    [self.pursuit giveChocolate];
}

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

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,737评论 0 14
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,922评论 1 15
  • 链接:https://github.com/WiKi123/DesignPattern作者: WiKi123(gi...
    树懒啊树懒阅读 3,477评论 0 2
  • “感恩的心” 郴州市永兴县塘门口中心学校“知心屋”2018年 第一期团体心理辅导活动于4月19日成功举行! 活动看...
    藕心竹节阅读 153评论 0 0
  • 早上老公送我上班,坐在车里一直迷迷糊糊,想要多睡一会儿,忽然老公猛的一刹车,惊得我腾的坐了起来,“你干嘛........
    小妮子秦阅读 225评论 0 0