狀態模式容許對象內部狀態改變時改變它的行爲,對象看起來好像修改了它的類。狀態模式看起來和策略模式比較相像,策略模式是將能夠互換的行爲封裝起來,而後經過使用委託的方式,決定使用哪個行爲,狀態也是封裝行爲,不一樣的是能夠將行爲委託到當前狀態。一個須要從外部設置,一個是內部經過狀態變動達到行爲變成的目的。測試
狀態模式的UML類圖:atom
State封裝基本的狀態行爲,咱們經過Cotext上下文持有狀態子類的實例,外部發起請求,咱們就能夠委託狀態進行處理。地鐵裏面通常都有自動飲料售賣機,咱們將全部的飲料都當作商品來看,咱們若是須要買飲料須要兩步,投幣,取貨,若是沒有商品還能夠退錢三種行爲,關於自動售賣機的存在無錢狀態,有錢狀態,售賣中狀態,已售罄狀態四種狀態,稍微思考一下,能夠看下面的具體實現。spa
狀態行爲基類: 設計
@protocol StateProtocol <NSObject> @optional -(void)putMoney; @optional -(void)ejectMoney; @optional -(void)pressButton; @optional -(void)distribute; @end @interface State : NSObject<StateProtocol> @end
售賣機處於無錢狀態(NoMoneyState):對象
@protocol NoMoneyDelegate <NSObject> -(void)setCurrentState:(State *)currentState; -(State *)geHasMoneyState; @end //沒錢狀態 @interface NoMoneyState : State @property (weak,nonatomic) id<NoMoneyDelegate> delegate; @end
@implementation NoMoneyState -(void)putMoney{ NSLog(@"NoMoneyState-putMoney:投放錢幣"); [self.delegate setCurrentState:[self.delegate geHasMoneyState]]; } -(void)ejectMoney{ NSLog(@"NoMoneyState-ejectMoney:沒有投入錢幣,沒法退錢"); } -(void)pressButton{ NSLog(@"NoMoneyState-pressButton:請先投幣"); } -(void)distribute{ NSLog(@"NoMoneyState-pressButton:請投幣"); } @end
售賣機處於有錢狀態(HasMoneyState):blog
@protocol HasMoneyDelegate <NSObject> -(void)setCurrentState:(State *)currentState; -(State *)getNoMoneyState; -(State *)getSoldState; @end //有錢狀態 @interface HasMoneyState : State @property (weak,nonatomic) id<HasMoneyDelegate> delegate; @end
@implementation HasMoneyState -(void)putMoney{ NSLog(@"HasMoneyState-putMoney:已經投入了錢,暫不支持投入"); } -(void)ejectMoney{ NSLog(@"HasMoneyState-ejectMoney:退錢,從新設置售賣機爲無前狀態"); [self.delegate setCurrentState:[self.delegate getNoMoneyState]]; } -(void)pressButton{ NSLog(@"HasMoneyState-pressButton:按鈕按下,取貨"); [self.delegate setCurrentState:[self.delegate getSoldState]]; } -(void)distribute{ NSLog(@"HasMoneyState-distribute:沒法進行取出商品"); } @end
售賣機處於售賣狀態:get
@protocol SoldDelegate <NSObject> -(void)setCurrentState:(State *)currentState; -(void)realseProduct; -(NSInteger)getCurrentCount; -(State *)getNoMoneyState; -(State *)getSoldOutState; @end //售出狀態 @interface SoldState : State @property (weak,nonatomic) id<SoldDelegate> delegate; @end
@implementation SoldState -(void)putMoney{ NSLog(@"SoldState-putMoney:請稍後,正在進行商品出售"); } -(void)ejectMoney{ NSLog(@"SoldState-putMoney:請稍後,正在進行商品出售,沒法退錢"); } -(void)pressButton{ NSLog(@"SoldState-putMoney:請在取出物品以後從新投幣"); } -(void)distribute{ [self.delegate realseProduct]; if ([self.delegate getCurrentCount]) { [self.delegate setCurrentState:[self.delegate getNoMoneyState]]; }else{ [self.delegate setCurrentState:[self.delegate getSoldOutState]]; } } @end
售罄狀態(SoldOutState):it
@protocol SoldOutDelegate <NSObject> -(void)setCurrentState:(State *)currentState; @end //售罄狀態 @interface SoldOutState : State @property (weak,nonatomic) id<SoldOutDelegate> delegate; @end
@implementation SoldOutState -(void)putMoney{ NSLog(@"SoldOutState-PutMoney:已售罄"); } -(void)ejectMoney{ NSLog(@"SoldOutState-ejectMoney:沒法退錢"); } -(void)pressButton{ NSLog(@"SoldOutState-pressButton:沒法售出"); } -(void)distribute{ NSLog(@"SoldOutState-distribute:沒法分發"); } @end
售賣機(SaleMachine):io
@interface SaleMachine : NSObject<NoMoneyDelegate,HasMoneyDelegate,SoldOutDelegate,SoldDelegate> @property (strong,nonatomic) NoMoneyState *noMoneyState; @property (strong,nonatomic) HasMoneyState *hasMoneyState; @property (strong,nonatomic) SoldOutState *soldOutState; @property (strong,nonatomic) SoldState *soldState; -(instancetype)initWithCount:(NSInteger)count; -(void)setCurrentState:(State *)currentState; -(void)putMoney; -(void)ejectMoney; -(void)pressButton; @end
@interface SaleMachine() @property (strong,nonatomic) State *state; @property (assign,nonatomic) NSInteger productCount; @end @implementation SaleMachine -(instancetype)initWithCount:(NSInteger)count{ self=[super init]; if (self) { self.noMoneyState=[[NoMoneyState alloc]init]; self.noMoneyState.delegate=self; self.hasMoneyState=[[HasMoneyState alloc]init]; self.hasMoneyState.delegate=self; self.soldState=[[SoldState alloc]init]; self.soldState.delegate=self; self.soldOutState=[[SoldOutState alloc]init]; self.soldOutState.delegate=self; self.productCount=count; if (count) { self.state=self.noMoneyState; } } return self; } -(void)putMoney{ [self.state putMoney]; } -(void)ejectMoney{ [self.state ejectMoney]; } -(void)pressButton{ [self.state pressButton]; [self.state distribute]; } -(void)setCurrentState:(State *)currentState{ self.state=currentState; } #pragma mark - NoMoenyDelegate -(State *)geHasMoneyState{ return self.hasMoneyState; } #pragma mark - HasMoneyDelegate -(State *)getNoMoneyState{ return self.noMoneyState; } -(State *)getSoldState{ return self.soldState; } #pragma mark - SoldDelegate -(void)realseProduct{ NSLog(@"SoldDelegate-realseProduct:商品售出"); if (self.productCount) { self.productCount-=1; } } -(State *)getSoldOutState{ return self.soldOutState; } -(NSInteger)getCurrentCount{ return self.productCount; } @end
測試:class
SaleMachine *machine=[[SaleMachine alloc]initWithCount:1]; [machine putMoney]; [machine ejectMoney]; [machine putMoney]; [machine pressButton]; SaleMachine *next=[[SaleMachine alloc]initWithCount:1]; [next putMoney]; [next ejectMoney];
測試效果:
狀態模式的優缺點:
優勢:狀態模式容許一個對象基於內部狀態有不一樣的行爲,將行爲委託給狀態對象執行,狀態轉化能夠由Context也能夠由狀態行爲控制,比較靈活;
缺點: 狀態模式的使用必然會增長系統類和對象的個數。狀態模式的結構與實現都較爲複雜,若是使用不當將致使程序結構和代碼的混亂。