讀《大話設計模式》二

結構型模式

適配器模式

模式動機

適配器提供客戶類需要的接口,適配器的實現就是把客戶類的請求轉化為對適配者的相應接口的調用。也就是說:當客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個過程對客戶類是透明的,客戶類并不直接訪問適配者類。因此,適配器可以使由于接口不兼容而不能交互的類可以一起工作。這就是適配器模式的模式動機。

模式定義

適配器模式:將一個接口轉換成客戶希望的另一個接口,適配器模式使接口不兼容的那些類可以一起工作,其別名為包裝器。適配器模式既可以作為類結構型模式,也可以作為對象結構型模式。

模式結構

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

  • 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
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 設計模式概述 在學習面向對象七大設計原則時需要注意以下幾點:a) 高內聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,771評論 0 14
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,961評論 1 15
  • 鏈接:https://github.com/WiKi123/DesignPattern作者: WiKi123(gi...
    樹懶啊樹懶閱讀 3,596評論 0 2
  • “感恩的心” 郴州市永興縣塘門口中心學校“知心屋”2018年 第一期團體心理輔導活動于4月19日成功舉行! 活動看...
    藕心竹節閱讀 161評論 0 0
  • 早上老公送我上班,坐在車里一直迷迷糊糊,想要多睡一會兒,忽然老公猛的一剎車,驚得我騰的坐了起來,“你干嘛........
    小妮子秦閱讀 230評論 0 0