讀《大話設計模式》三

行為型模式

迭代器模式

模式動機

針對不同的需要,可能還要以不同的方式遍歷整個聚合對象,但是我們并不希望在聚合對象的抽象層接口中充斥著各種不同遍歷的操作。
怎樣遍歷一個聚合對象,又不需要了解聚合對象的內(nèi)部結(jié)構(gòu),還能夠提供多種不同的遍歷方式,這就是迭代器模式的模式動機。

模式定義

提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內(nèi)部表示。

模式結(jié)構(gòu)

模板方法模式包含如下角色:

  • Aggregate: 聚集抽象類
  • ConcreteAggregate: 具體聚集類
  • Iterator: 迭代抽象類
  • ConcreteIterator: 具體迭代器類
迭代器模式類圖
時序圖

源碼

行為型

命令模式

模式動機

在軟件設計中,我們經(jīng)常需要向某些對象發(fā)送請求,但是并不知道請求的接收者是誰,也不知道被請求的操作是哪個,我們只需在程序運行時指定具體的請求接收者即可,此時,可以使用命令模式來進行設計,使得請求發(fā)送者與請求接收者消除彼此之間的耦合,讓對象之間的調(diào)用關系更加靈活。

命令模式可以對發(fā)送者和接收者完全解耦,發(fā)送者與接收者之間沒有直接引用關系,發(fā)送請求的對象只需要知道如何發(fā)送請求,而不必知道如何完成請求。這就是命令模式的模式動機。

模式定義

命令模式(Command Pattern):將一個請求封裝為一個對象,從而使我們可用不同的請求對客戶進行參數(shù)化;對請求排隊或者記錄請求日志,以及支持可撤銷的操作。命令模式是一種對象行為型模式,其別名為動作(Action)模式或事務(Transaction)模式。

模式結(jié)構(gòu)

命令模式包含如下角色:

  • Command: 抽象命令類
  • ConcreteCommand: 具體命令類
  • Invoker: 調(diào)用者
  • Receiver: 接收者
  • Client:客戶類


    命令模式類圖
時序圖
命令模式時序圖
源碼
//使用示例
    //waiter用于接收各種類型的order。waiter是請求接收者。
    //接收不同customer產(chǎn)生的不同order,并且都存入waiter這個接受者中,type表示不同類型的order。
    HCDWaiter *waiter = [[HCDWaiter alloc]init];
    
    //顧客一
    HCDCustomr *customer = [[HCDCustomr alloc]init];
    HCDOrder *customerOrder1 = [customer pushOrderWithString:@"顧客一要十串羊肉" type:orderTypeMutton];
    HCDOrder *customerOrder2 = [customer pushOrderWithString:@"顧客一要十串鴨肉" type:orderTypeDuck];
    [waiter addOrder:customerOrder1];
    [waiter addOrder:customerOrder2];
    
    //顧客二
    HCDCustomr *customer1 = [[HCDCustomr alloc]init];
    HCDOrder *customer1Order1 = [customer1 pushOrderWithString:@"顧客二要二十串雞肉" type:orderTypeChicken];
    HCDOrder *customer1Order2 = [customer1 pushOrderWithString:@"顧客二要二十串鴨肉" type:orderTypeDuck];
    [waiter addOrder:customer1Order1];
    [waiter addOrder:customer1Order2];
    [waiter deleteOrder:customer1Order2];
    
    //waiter發(fā)送order,背后有一個HCDWorker這個單列作為行為實現(xiàn)者來處理具體的order。命令接收完畢,開始發(fā)送命令。
    [waiter notifyOrder];
//HCDCustomr.m
@implementation HCDCustomr

-(HCDOrder *)pushOrderWithString:(NSString *)string type:(orderType)type{
    HCDOrder *order = nil;
    switch (type) {
        case orderTypeMutton:
            order = [[HCDMuttonOrder alloc]initWithOrderString:string];
            break;
        case orderTypeChicken:
            order = [[HCDChickenOrder alloc]initWithOrderString:string];
            break;
        case orderTypeDuck:
            order = [[HCDDuckOrder alloc]initWithOrderString:string];
            break;
    }
    return order;
}
@end
//HCDWaiter.m
@implementation HCDWaiter

-(instancetype)init{
    self = [super init];
    if (self) {
        _orderList = [NSMutableArray array];
    }
    return self;
}
-(void)addOrder:(HCDOrder *)order{
    NSLog(@"添加Order");
    [self.orderList addObject:order];
}
-(void)deleteOrder:(HCDOrder *)order{
    NSLog(@"取消Order");
    [self.orderList removeObject:order];
}
/*
 命令接收完畢,開始執(zhí)行命令
 */
-(void)notifyOrder{
    NSLog(@"====開始執(zhí)行Order===");
    for (HCDOrder *order in self.orderList) {
        [order executeOrder];
    }
}
@end
//HCDOrder.h
@interface HCDOrder : NSObject

@property(nonatomic,copy)NSString *orderString;

-(instancetype)initWithOrderString:(NSString *)orderString;
//執(zhí)行命令
-(void)executeOrder;

@end

//HCDMuttonOrder.m
@implementation HCDMuttonOrder

-(void)executeOrder{
    NSLog(@"烤羊");
    [[HCDWorker sharedWorker] doMuttonWork:self.orderString];
}
@end

//HCDChickenOrder.m
@implementation HCDChickenOrder

-(void)executeOrder{
    NSLog(@"烤雞");
    [[HCDWorker sharedWorker] doChickenWork:self.orderString];
}

@end

//HCDDuckOrder.m
@implementation HCDDuckOrder

-(void)executeOrder{
    NSLog(@"烤鴨");
    [[HCDWorker sharedWorker] doChickenWork:self.orderString];
}

@end 
//HCDWorker.h
@interface HCDWorker : NSObject

+(instancetype)sharedWorker;

-(void)doMuttonWork:(NSString *)work;

-(void)doChickenWork:(NSString *)work;

-(void)doDuckWork:(NSString *)work;

@end

中介者模式

模式動機
  • 在用戶與用戶直接聊天的設計方案中,用戶對象之間存在很強的關聯(lián)性,將導致系統(tǒng)出現(xiàn)如下問題:
  • 系統(tǒng)結(jié)構(gòu)復雜:對象之間存在大量的相互關聯(lián)和調(diào)用,若有一個對象發(fā)生變化,則需要跟蹤和該對象關聯(lián)的其他所有對象,并進行適當處理。
  • 對象可重用性差:由于一個對象和其他對象具有很強的關聯(lián),若沒有其他對象的支持,一個對象很難被另一個系統(tǒng)或模塊重用,這些對象表現(xiàn)出來更像一個不可分割的整體,職責較為混亂。
  • 系統(tǒng)擴展性低:增加一個新的對象需要在原有相關對象上增加引用,增加新的引用關系也需要調(diào)整原有對象,系統(tǒng)耦合度很高,對象操作很不靈活,擴展性差。
  • 在面向?qū)ο蟮能浖O計與開發(fā)過程中,根據(jù)“單一職責原則”,我們應該盡量將對象細化,使其只負責或呈現(xiàn)單一的職責。
  • 對于一個模塊,可能由很多對象構(gòu)成,而且這些對象之間可能存在相互的引用,為了減少對象兩兩之間復雜的引用關系,使之成為一個松耦合的系統(tǒng),我們需要使用中介者模式,這就是中介者模式的模式動機。
模式定義

中介者模式(Mediator Pattern)定義:用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。它是一種對象行為型模式。

模式結(jié)構(gòu)

中介者模式包含如下角色:

  • Mediator: 抽象中介者
  • ConcreteMediator: 具體中介者
  • Colleague: 抽象同事類
  • ConcreteColleague: 具體同事類


    中介者模式類圖
時序圖
中介者模式時序圖
源碼
    //使用示例
    ConcreteMediator *mediator = [[ConcreteMediator alloc] init];
    
    //初始化并且讓兩個同事有相同的中介者對象
    ConcreteColleague1 *c1 = [[ConcreteColleague1 alloc] initWithMediator:mediator];
    ConcreteColleague2 *c2 = [[ConcreteColleague2 alloc] initWithMediator:mediator];
    
    //給中介者對象綁定兩個要交互的同事對象
    mediator.colleague1 = c1;
    mediator.colleague2 = c2;
    
    [c1 send:@"吃過飯了嗎?"];
    [c2 send:@"沒有呢,你打算請客?"];
//Mediator.h
@class Colleague;
@interface Mediator : NSObject

@property (nonatomic, strong) Colleague *colleague1;
@property (nonatomic, strong) Colleague *colleague2;

-(void)send:(NSString *)message colleague:(Colleague *)colleague;

@end
//ConcreteMediator.m
@implementation ConcreteMediator

-(void)send:(NSString *)message colleague:(Colleague *)colleague{
    if (colleague == self.colleague1) {
        [self.colleague2 notify:message];
    }else{
        [self.colleague1 notify:message];
    }
}

@end
//Colleague.h
@class Mediator;
@interface Colleague : NSObject

@property(nonatomic, strong) Mediator *mediator;

-(instancetype)initWithMediator:(Mediator *)mediator;

-(void)notify:(NSString *)message;

-(void)send:(NSString *)message;

@end
//ConcreteColleague1.m
@implementation ConcreteColleague1

-(instancetype)initWithMediator:(Mediator *)mediator{
    self = [super init];
    if (self) {
        self.mediator = mediator;
    }
    return self;
}

-(void)send:(NSString *)message{
    NSLog(@"同事1發(fā)送了信息");
    [self.mediator send:message colleague:self];
}

-(void)notify:(NSString *)message{
    NSLog(@"%@%@",@"同事1得到消息:", message);
}

@end
//ConcreteColleague2.m
@implementation ConcreteColleague2

-(instancetype)initWithMediator:(Mediator *)mediator{
    self = [super init];
    if (self) {
        self.mediator = mediator;
    }
    return self;
}

-(void)send:(NSString *)message{
    NSLog(@"同事2發(fā)送了信息");
    [self.mediator send:message colleague:self];
}

-(void)notify:(NSString *)message{
    NSLog(@"%@%@",@"同事2得到消息", message);
}

@end

觀察者模式

模式動機

建立一種對象與對象之間的依賴關系,一個對象發(fā)生改變時將自動通知其他對象,其他對象將相應做出反應。在此,發(fā)生改變的對象稱為觀察目標,而被通知的對象稱為觀察者,一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯(lián)系,可以根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴展,這就是觀察者模式的模式動機。

模式定義

觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關系,使得每當一個對象狀態(tài)發(fā)生改變時,其相關依賴對象皆得到通知并被自動更新。觀察者模式是一種對象行為型模式。

模式結(jié)構(gòu)

觀察者模式包含如下角色:

  • Subject: 目標
  • ConcreteSubject: 具體目標
  • Observer: 觀察者
  • ConcreteObserver: 具體觀察者


    觀察者模式類圖
時序圖
觀察者模式時序圖
源碼
//使用示例
- (void)viewDidLoad {
    [super viewDidLoad];
    
    HCDServiceCenter *serviceCenter = [[HCDServiceCenter alloc] init];
    
    [serviceCenter addDelegate:self.nbaobserver];
    [serviceCenter addDelegate:self.stockobserver];
    [serviceCenter addDelegate:self.gameObserver];
    
    NSLog(@"秘書通知:老板回來了,大家趕緊撤"); 
    [serviceCenter notifyServiceDelegate:@selector(update)
                                 perform:^(id responder) {
                                     [responder update];
    }];
}

#pragma mark - getter & setter

-(HCDNBAObserver *)nbaobserver {
    if (!_nbaobserver) {
        _nbaobserver = [[HCDNBAObserver alloc] init];
    }
    return _nbaobserver;
}

-(HCDStockObserver *)stockobserver {
    if (!_stockobserver) {
      _stockobserver = [[HCDStockObserver alloc] init];
    }
    return _stockobserver;
}

-(HCDGameObserver *)gameObserver {
    if (!_gameObserver) {
        _gameObserver = [[HCDGameObserver alloc] init];
    }
    return _gameObserver;
}
//HCDServiceCenter.h
@interface HCDServiceCenter : NSObject

@property(nonatomic, strong, readonly) NSHashTable *responders;

- (instancetype)initWithNotifyQueue:(dispatch_queue_t)notifyQueue;

- (void)addDelegate:(id)delegate;

- (void)removeDelegate:(id)delegate;

- (void)notifyServiceDelegate:(SEL)aSelector
                      perform:(void (^)(id responder))perform;

@end
//HCDServiceCenter.m
#define LOCK(...) dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
__VA_ARGS__; \
dispatch_semaphore_signal(_lock);

@interface HCDServiceCenter()

@property(nonatomic, strong) dispatch_queue_t notifyQueue;

@property(nonatomic, strong) NSHashTable *responders;

@end

@implementation HCDServiceCenter {
    dispatch_semaphore_t _lock;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        self.responders = [NSHashTable weakObjectsHashTable];
        self.notifyQueue = dispatch_get_main_queue();
        _lock = dispatch_semaphore_create(1);
    }
    return self;
}

- (instancetype)initWithNotifyQueue:(dispatch_queue_t)notifyQueue {
    self = [super init];
    if (self) {
        self.responders = [NSHashTable weakObjectsHashTable];
        self.notifyQueue = notifyQueue;
    }
    return self;
}

- (void)addDelegate:(id)delegate { 
    LOCK([self.responders addObject:delegate]);
}

- (void)removeDelegate:(id)delegate {
    LOCK([self.responders removeObject:delegate]); 
}

- (void)notifyServiceDelegate:(SEL)aSelector
                      perform:(void (^)(id responder))perform {
    dispatch_async(self.notifyQueue, ^{
        NSArray *responders = self.responders.allObjects;
        for (id responder in responders) {
            if ([responder respondsToSelector:aSelector]) {
                @try {
                    perform(responder);
                }
                @catch (NSException *exception) {
                    NSLog(@"catch notifyServiceDelegate exception: %@", exception);
                }
            }
        }
    });
}

@end
//HCDObserver.h
@protocol HCDObserver <NSObject>

@optional
- (void)update;

@end

//HCDStockObserver.h
@interface HCDStockObserver : NSObject<HCDObserver>

@end

//HCDNBAObserver.h
@interface HCDNBAObserver : NSObject<HCDObserver>

@end

//HCDGameObserver.h
@interface HCDGameObserver : NSObject<HCDObserver>

@end

狀態(tài)模式

模式動機

在很多情況下,一個對象的行為取決于一個或多個動態(tài)變化的屬性,這樣的屬性叫做狀態(tài),這樣的對象叫做有狀態(tài)的(stateful)對象,這樣的對象狀態(tài)是從事先定義好的一系列值中取出的。當一個這樣的對象與外部事件產(chǎn)生互動時,其內(nèi)部狀態(tài)就會改變,從而使得系統(tǒng)的行為也隨之發(fā)生變化。

狀態(tài)模式主要解決的是當控制一個對象狀態(tài)轉(zhuǎn)換的條件表達式過于負責時的情況。把狀態(tài)的判斷邏輯轉(zhuǎn)移到表示不同狀態(tài)的一系列類當中,可以把復雜的判斷邏輯簡化。

模式定義

允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類。狀態(tài)模式是一種對象行為型模式。

模式結(jié)構(gòu)

狀態(tài)模式包含如下角色:

  • Context: 環(huán)境類
  • State: 抽象狀態(tài)類
  • ConcreteState: 具體狀態(tài)類


    狀態(tài)模式類圖
時序圖
狀態(tài)模式時序圖
源碼
    //使用示例
    HCDWork *work = [[HCDWork alloc]init];
    work.hour = 9;
    [work writeProgram];
    
    work.hour = 10;
    [work writeProgram];
    
    work.hour = 12;
    [work writeProgram];
    
    work.hour = 13;
    [work writeProgram];
    
    work.hour = 14;
    [work writeProgram];
    
    work.hour = 17;
    [work writeProgram];
    
    work.finished = NO;
    [work writeProgram];
    
    work.hour = 19;
    [work writeProgram];
    
    work.hour = 22;
    [work writeProgram];
//HCDWork.h
@interface HCDWork : NSObject

@property(nonatomic, assign) CGFloat hour;

@property(nonatomic, assign) BOOL finished;

- (void)writeProgram;

- (void)changeState:(HCDState *)state;

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

@property (nonatomic, strong) HCDState *state;

@end

@implementation HCDWork

- (instancetype)init{
    self = [super init];
    if (self) {
        self.state = [[HCDForenoonState alloc]init];
    }
    return self;
}

- (void)writeProgram {
    [self.state writeProgram:self];
}

- (void)changeState:(HCDState *)state {
    self.state = state;
}

@end
//HCDProtocol.h
@class HCDWork;
@protocol HCDProtocol <NSObject>

@optional
- (void)writeProgram:(HCDWork *)work;

@end
//HCDState.h
@interface HCDState : NSObject<HCDProtocol>

@end
//HCDForenoonState.m
@implementation HCDForenoonState

-(void)writeProgram:(HCDWork *)work{
    if (work.hour < 12) {
         NSLog(@"當前時間:{%.f}點,上午工作,精神百倍", work.hour);
    }else{
        HCDNoonState *noonState = [[HCDNoonState alloc] init];
        [work changeState:noonState];
        [work writeProgram];
    }
}
@end
//HCDNoonState.m
@implementation HCDNoonState

-(void)writeProgram:(HCDWork *)work{
    if (work.hour < 13) {
        NSLog(@"當前時間:{%.f}點,餓了,午飯;犯困,午休", work.hour);
    } else {
        HCDAfternoonState *afternoonState = [[HCDAfternoonState alloc] init];
        [work changeState:afternoonState];
        [work writeProgram];
    }
}
@end
//HCDAfternoonState.m
@implementation HCDAfternoonState

-(void)writeProgram:(HCDWork *)work{
    if (work.hour < 17) {
        NSLog(@"當前時間:{%.f}點,下午狀態(tài)還不錯,繼續(xù)努力", work.hour);
    } else {
        HCDEventState *eventState = [[HCDEventState alloc] init];
        [work changeState:eventState];
        [work writeProgram];
    }
}
@end
//HCDEventState.m
@implementation HCDEventState

-(void)writeProgram:(HCDWork *)work{
    if (work.finished) {
        HCDRestState *restState = [[HCDRestState alloc] init];
        [work changeState:restState];
        [work writeProgram];
    } else {
        if (work.hour < 21) {
            NSLog(@"當前時間:{%.f}點,加班哦,疲累之極", work.hour);
        } else {
            HCDSleepState *sleepState = [[HCDSleepState alloc] init];
            [work changeState:sleepState]; 
            [work writeProgram];
        }
    }

}

@end
//HCDSleepState.m
@implementation HCDSleepState

- (void)writeProgram:(HCDWork *)work {
    NSLog(@"當前時間:{%.f}點,不行了,睡著了", work.hour);
}
@end
//HCDRestState.m
@implementation HCDRestState

- (void)writeProgram:(HCDWork *)work {
    NSLog(@"當前時間:{%.f}點,下班回家了", work.hour);
}
@end

策略模式

模式動機
  • 完成一項任務,往往可以有多種不同的方式,每一種方式稱為一個策略,我們可以根據(jù)環(huán)境或者條件的不同選擇不同的策略來完成該項任務。
  • 在軟件開發(fā)中也常常遇到類似的情況,實現(xiàn)某一個功能有多個途徑,此時可以使用一種設計模式來使得系統(tǒng)可以靈活地選擇解決途徑,也能夠方便地增加新的解決途徑。
  • 為了解決這些問題,可以定義一些獨立的類來封裝不同的算法,每一個類封裝一個具體的算法,在這里,每一個封裝算法的類我們都可以稱之為策略(Strategy),為了保證這些策略的一致性,一般會用一個抽象的策略類來做算法的定義,而具體每種算法則對應于一個具體策略類。
模式定義

定義了算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化,不會影響到使用算法的客戶。

模式結(jié)構(gòu)

策略模式包含如下角色:

  • Context: 環(huán)境類
  • Strategy: 抽象策略類
  • ConcreteStrategy: 具體策略類
策略模式類圖
時序圖
策略模式時序圖
源碼
    //使用示例
    HCDCashContext *context = [[HCDCashContext alloc] initWithCashType:HCDCashTypeNormal];
    NSLog(@"結(jié)果是%f",[context getResult:100]);

    HCDCashContext *contextReturn = [[HCDCashContext alloc] initWithCashType:HCDCashTypeReturn];
    NSLog(@"結(jié)果是%f",[contextReturn getResult:100]);
    
    HCDCashContext *contextRobate = [[HCDCashContext alloc] initWithCashType:HCDCashTypeRobate];
    NSLog(@"結(jié)果是%f",[contextRobate getResult:100]);
//HCDCashContext.h
typedef NS_ENUM(NSInteger, HCDCashType){
    HCDCashTypeNormal = 0,
    HCDCashTypeRobate,
    HCDCashTypeReturn
};

@interface HCDCashContext : NSObject 

-(instancetype)initWithCashType:(HCDCashType)type;

-(CGFloat)getResult:(CGFloat)money;

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

@property (nonatomic, strong) id<HCDCashProtocol> cash;

@end

@implementation HCDCashContext 

-(instancetype)initWithCashType:(HCDCashType)type{
    self = [super init];
    if (self) {
        [self cofigureWithCashType:type];
    }
    return self;
}

- (void)cofigureWithCashType:(HCDCashType)type {
    switch (type) {
        case HCDCashTypeNormal: {
            self.cash = [[HCDCashNormal alloc] init];
        }
        break;
        case HCDCashTypeRobate: {
            self.cash = [[HCDCashRobate alloc] initWithMoneyRebate:0.8];
        }
        break;
        case HCDCashTypeReturn: {
            self.cash = [[HCDCaseReturn alloc] initWithMoneyReturn:5];
        }
        break;
    }
}

- (CGFloat)getResult:(CGFloat)money {
    return [self.cash acceptCash:money];
}

@end
//HCDCashProtocol.h
@protocol HCDCashProtocol <NSObject>

- (CGFloat)acceptCash:(CGFloat)cash;

@end
//HCDCaseReturn.h
@interface HCDCaseReturn : NSObject<HCDCashProtocol>

-(instancetype)initWithMoneyReturn:(CGFloat)moneyReturn;

@end

//HCDCaseReturn.m
@interface HCDCaseReturn ()

@property (nonatomic, assign)CGFloat moneyReturn;

@end

@implementation HCDCaseReturn

#pragma mark - life cycle

-(instancetype)initWithMoneyReturn:(CGFloat)moneyReturn{
    self = [super init];
    if (self) {
        _moneyReturn = moneyReturn;
    }
    return self;
}

#pragma mark - HCDCashProtocol

-(CGFloat)acceptCash:(CGFloat)cash{
    return cash - self.moneyReturn;
}

@end
//HCDCashNormal.m
@implementation HCDCashNormal
 
-(CGFloat)acceptCash:(CGFloat)cash{
    return cash;
}

@end
//HCDCashRobate.h
@interface HCDCashRobate : NSObject<HCDCashProtocol>

-(instancetype)initWithMoneyRebate:(CGFloat)moneyRebate;

@end

//HCDCashRobate.m
@interface HCDCashRobate ()

@property (nonatomic, assign) CGFloat moneyRebate;

@end

@implementation HCDCashRobate

-(instancetype)initWithMoneyRebate:(CGFloat)moneyRebate{
    self = [super init];
    if (self) {
        _moneyRebate = moneyRebate;
    }
    return self;
}

-(CGFloat)acceptCash:(CGFloat)cash{
    return self.moneyRebate * cash;
}

@end

模板方法模式

模式動機

模板方法模式是基于繼承的代碼復用基本技術(shù),模板方法模式的結(jié)構(gòu)和用法也是面向?qū)ο笤O計的核心之一。
在模板方法模式中,可以將相同的代碼放在父類中,而將不同的方法實現(xiàn)放在不同的子類中。

模式定義

定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

模式結(jié)構(gòu)

模板方法模式包含如下角色:

  • AbstractClass: 抽象類
  • ConcreteClass: 具體子類


    模板方法模式類圖
時序圖

源碼
    //使用示例
    HCDtextPaper *paperA = [[HCDtextPaperA alloc]init];
    [paperA testQuestion1];
    [paperA testQuestion2];
    
    HCDtextPaper *paperB = [[HCDtextPaperB alloc]init];
    [paperB testQuestion1];
    [paperB testQuestion2];
//HCDtextPaper.h
@interface HCDtextPaper : NSObject

- (void)testQuestion1;

- (void)testQuestion2;

/**
 子類需要重寫這個方法

 @return 結(jié)果
 */
- (NSString *)answer1;

/**
 子類需要重寫這個方法
 
 @return 結(jié)果
 */
- (NSString *)answer2;

@end
//HCDtextPaper.m
@implementation HCDtextPaper

-(void)testQuestion1 {
    NSLog(@"問題:楊過得到,后來給了郭靖,煉成倚天劍、屠龍刀的玄鐵可能是[ ]:a.球磨鑄鐵 b.馬口鐵 c.高速合金鋼 d.碳素纖維");
    NSLog(@"答案:%@", [self answer1]);
}

-(NSString *)answer1 {
    return @"";
}

-(void)testQuestion2 {
    NSLog(@"問題:楊過、程英、陸無雙鏟除了情花,造成[ ]:a.使這種植物不再害人 b.使一種珍稀物種滅絕 c.破壞了那個生物圈的生態(tài)平衡 d.造成該地區(qū)沙漠化");
    NSLog(@"答案:%@", [self answer2]);
}

-(NSString *)answer2{
    return @"";
}

@end
//HCDtextPaperA.m
@implementation HCDtextPaperA

-(NSString *)answer1{
    return @"b";
}

-(NSString *)answer2{
    return @"c";
}

@end
//HCDtextPaperB.m
@implementation HCDtextPaperB

-(NSString *)answer1{
    return @"a";
}

-(NSString *)answer2{
    return @"d";
}

@end

職責鏈模式

模式動機

很多情況下,在一個軟件系統(tǒng)中可以處理某個請求的對象不止一個。例如采購審批子系統(tǒng),主任、副董事長、董事長和董事會都可以處理采購單,他們可以構(gòu)成一條處理采購單的鏈式結(jié)構(gòu),采購單(可以看作是要處理的信息)沿著這條鏈進行傳遞,這條鏈就稱為責任鏈。責任鏈可以是一條直線、一個環(huán)或者一個樹形結(jié)構(gòu),最常見的職責鏈是直線型,即沿著一條單向的鏈來傳遞請求,如下圖所示。鏈上的每一個對象都是請求處理者,責任鏈模式可以將請求的處理者組織成一條鏈,并讓請求沿著鏈傳遞,由鏈上的處理者對請求進行相應的處理。在此過程中,客戶端實際上無須關心請求的處理細節(jié)以及請求的傳遞,只需將請求發(fā)送到鏈上即可,從而實現(xiàn)請求發(fā)送者和請求處理者解耦。

模式定義

使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接受者之間的耦合關系。將這個對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。

模式結(jié)構(gòu)

職責鏈模式包含如下角色:

  • Handler: 處理者抽象類
  • ConcreteAggregate: 具體處理者類
職責鏈模式類圖
時序圖

源碼
    //使用示例
    HCDCommonManager *jinli = [[HCDCommonManager alloc]initWithName:@"經(jīng)理"];
    HCDMajorManager *zongjian = [[HCDMajorManager alloc]initWithName:@"總監(jiān)"];
    HCDGenaralManager *zongjinli = [[HCDGenaralManager alloc]initWithName:@"總經(jīng)理"];
    jinli.superior = zongjian;
    zongjian.superior = zongjinli;
    
    HCDReuquest *request = [[HCDReuquest alloc] init];
    request.requestType = @"請假";
    request.requestContent = @"小菜請假";
    request.number = 1;
    [jinli dealRequest:request];
    
    HCDReuquest *request1 = [[HCDReuquest alloc] init];
    request1.requestType = @"請假";
    request1.requestContent = @"小菜請假";
    request1.number = 4;
    [jinli dealRequest:request1];
    
    HCDReuquest *request2 = [[HCDReuquest alloc] init];
    request2.requestType = @"加薪";
    request2.requestContent = @"小菜請求加薪";
    request2.number = 500;
    [jinli dealRequest:request2];
    
    HCDReuquest *request4 = [[HCDReuquest alloc] init];
    request4.requestType = @"加薪";
    request4.requestContent = @"小菜請求加薪";
    request4.number = 1000;
    [jinli dealRequest:request4];
//HCDMnager.h
@class HCDReuquest;
@interface HCDMnager : NSObject

@property (nonatomic, copy) NSString *name;

@property (nonatomic, strong) HCDMnager *superior;

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

- (void)dealRequest:(HCDReuquest *)request;

@end
//HCDCommonManager.h
@interface HCDCommonManager : HCDMnager

@end

//HCDCommonManager.m
@implementation HCDCommonManager

- (void)dealRequest:(HCDReuquest *)request{
    if ([request.requestType isEqualToString:@"請假"] && request.number <= 2) {
        NSLog(@"%@:%@ 數(shù)量%ld 被批準",self.name,request.requestType,request.number);
    }else{
        if (self.superior) {
            [self.superior dealRequest:request]; 
        }
    }
}

@end
//HCDMajorManager.h
@interface HCDMajorManager : HCDMnager

@end

//HCDMajorManager.m
@implementation HCDMajorManager

-(void)dealRequest:(HCDReuquest *)request{
    if ([request.requestType isEqualToString:@"請假"] && request.number <= 5) {
        NSLog(@"%@:%@ 數(shù)量%ld 被批準",self.name,request.requestType,request.number);
    }else{
        if (self.superior) {
            [self.superior dealRequest:request];
        }
    }
}
@end
//HCDGenaralManager.h
@interface HCDGenaralManager : HCDMnager

@end

//HCDGenaralManager.m
@implementation HCDGenaralManager

-(void)dealRequest:(HCDReuquest *)request{
    if ([request.requestType isEqualToString:@"請假"]) {
        NSLog(@"%@:%@ 數(shù)量%ld 被批準",self.name,request.requestType,request.number);
    } else if ([request.requestType isEqualToString:@"加薪"]){
        if (request.number <= 500) {
            NSLog(@"%@:%@ 數(shù)量%ld 被批準",self.name,request.requestType,request.number);
        } else {
            NSLog(@"%@:%@ 數(shù)量%ld 再說吧",self.name,request.requestType,request.number);
        }
    } else {
        
    }
}

@end
//HCDReuquest.h
@interface HCDReuquest : NSObject

/**
 請求類型
 */
@property (nonatomic, copy) NSString *requestType;

/**
 請求內(nèi)容
 */
@property (nonatomic, copy) NSString *requestContent;

/**
 請求的數(shù)量
 */
@property(nonatomic, assign) NSInteger number;

@end

解釋器模式

模式動機

如果在系統(tǒng)中某一特定類型的問題發(fā)生的頻率很高,此時可以考慮將這些問題的實例表述為一個語言中的句子,因此可以構(gòu)建一個解釋器,該解釋器通過解釋這些句子來解決這些問題。
解釋器模式描述了如何構(gòu)成一個簡單的語言解釋器,主要應用在使用面向?qū)ο笳Z言開發(fā)的編譯器中。

模式定義

給定一種語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。

模式結(jié)構(gòu)

解釋器模式模式包含如下角色:

  • AbstractExpression: 抽象表達式
  • TerminalExpression: 終結(jié)符表達式
  • NonterminalExpression: 非終結(jié)符表達式
  • Context: 環(huán)境類
  • Client: 客戶類


    解釋器模式類圖
時序圖

源碼

訪問者模式

模式動機

訪問者模式的目的是封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作,一旦這些操作需要修改的話,接受這個操作的數(shù)據(jù)結(jié)構(gòu)可以保持不變。為不同類型的元素提供多種訪問操作方式,且可以在不修改原有系統(tǒng)的情況下增加新的操作方式,這就是訪問者模式的模式動機。

模式定義

表示一個作用于某對象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。

模式結(jié)構(gòu)

訪問者模式包含如下角色:

  • Vistor: 抽象訪問者。為該對象結(jié)構(gòu)中的ConcreteElement的每一個類聲明的一個操作。
  • ConcreteVisitor: 具體訪問者。實現(xiàn)Visitor申明的每一個操作,每一個操作實現(xiàn)算法的一部分。
  • Element: 抽象元素。定義一個Accept操作,它以一個訪問者為參數(shù)。
  • ConcreteElement: 具體元素 。實現(xiàn)Accept操作。
  • ObjectStructure: 對象結(jié)構(gòu)。能夠枚舉它的元素,可以提供一個高層的接口來允許訪問者訪問它的元素。


    訪問者模式類圖
時序圖

源碼
    //使用示例
    HCDObjectStructure *o = [[HCDObjectStructure alloc]init];
    
    //初始化不同的element對象
    HCDConcreteElementA *eA = [HCDConcreteElementA new];
    HCDConcreteElementB *eB = [HCDConcreteElementB new];
    //加入o對象里面,存在一個數(shù)據(jù)結(jié)構(gòu)o中。
    [o attach:eA];
    [o attach:eB];
    
    //初始化不同的visitor對象。
    HCDConcreteVisitor1 *v1 = [HCDConcreteVisitor1 new];
    HCDConcreteVisitor2 *v2 = [HCDConcreteVisitor2 new];
    //eA,eB(男人女人)接收到訪問者v1(喜)的不同反應。
    [o accept:v1];
    NSLog(@"================================");
    //eA,eB(男人女人)接收到訪問者v2(怒)的不同反應。
    [o accept:v2];
//HCDObjectStructure.h
@class HCDElements;
@class HCDVisitors;

@interface HCDObjectStructure : NSObject

-(void)attach:(HCDElements *)element;

-(void)detach:(HCDElements *)element;

-(void)accept:(HCDVisitors *)visitor;

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

@property (nonatomic, strong) NSMutableArray *elements;

@end

@implementation HCDObjectStructure

-(instancetype)init{
    self = [super init];
    if (self) {
        _elements = [[NSMutableArray alloc]init];
    }
    return self;
}

-(void)attach:(HCDElements *)element{
    [self.elements addObject:element];
}

-(void)detach:(HCDElements *)element{
    [self.elements removeObject:element];
}

-(void)accept:(HCDVisitors *)visitor{
    for (HCDElements *e in self.elements) {
        [e accept:visitor];
    }
}

@end
//HCDVisitors.h
@interface HCDVisitors : NSObject

-(void)visitConcreteElementA:(HCDConcreteElementA *)concreteElementA;

-(void)visitConcreteElementB:(HCDConcreteElementB *)concreteElementB;

@end

//HCDConcreteVisitor1.h
@interface HCDConcreteVisitor1 : HCDVisitors

@end

//HCDConcreteVisitor1.m
@implementation HCDConcreteVisitor1

-(void)visitConcreteElementA:(HCDConcreteElementA *)concreteElementA{
    NSLog(@"男人接收到喜這個visitor============我要飛");
}

-(void)visitConcreteElementB:(HCDConcreteElementB *)concreteElementB{
    NSLog(@"女人接收到喜這個visitor============我要跳");
}

@end

//HCDConcreteVisitor2.h
@interface HCDConcreteVisitor2 : HCDVisitors

@end

//HCDConcreteVisitor2.m
@implementation HCDConcreteVisitor2

-(void)visitConcreteElementA:(HCDConcreteElementA *)concreteElementA{
    NSLog(@"男人接收到怒這個visitor============我要叫");
}

-(void)visitConcreteElementB:(HCDConcreteElementB *)concreteElementB{
    NSLog(@"女人接收到怒這個visitor============我要苦");
}

@end
//HCDElements.h
@class HCDVisitors;
@interface HCDElements : NSObject

-(void)accept:(HCDVisitors *)visitor;

@end
//HCDConcreteElementA.m
@implementation HCDConcreteElementA

-(void)operationA{
    return;
}

-(void)accept:(HCDVisitors *)visitor{
    [visitor visitConcreteElementA:self];
}

@end
//HCDConcreteElementB.m
@implementation HCDConcreteElementB

-(void)operationB{
    return;
}

-(void)accept:(HCDVisitors *)visitor{
    [visitor visitConcreteElementB:self];
}

@end

小結(jié)

在實際的項目開發(fā)過程中,使用某些特定的設計模式能夠很好的解決問題。同時,在維護他人編寫的代碼時,如果對設計模式特別熟悉,遇到時也比較容易定位問題。
源碼和demo請點這里
參考的文章鏈接如下
Graphic Design Patterns

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 設計模式概述 在學習面向?qū)ο笃叽笤O計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,898評論 0 14
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 4,096評論 1 15
  • 設計模式基本原則 開放-封閉原則(OCP),是說軟件實體(類、模塊、函數(shù)等等)應該可以拓展,但是不可修改。開-閉原...
    西山薄涼閱讀 4,086評論 3 14
  • 前言 對設計模式的理解,不夠透徹,有時去找資料,總是零零散散,不成系統(tǒng),故將《大話設計模式》中的干貨整理下,方便需...
    LeverTsui閱讀 720評論 0 1
  • 去年看了《敦刻爾克》。說實話大半時候豆瓣的評分都是蠻靠譜的。藝術(shù)來源于生活,敦刻爾克作為二戰(zhàn)的一個片斷,是值得記憶...
    彼岸流星閱讀 275評論 0 2

友情鏈接更多精彩內(nèi)容