状态模式(State)

参考博客iOS App的设计模式开发中对State状态模式的运用

使用场景:

例子1:按钮来控制一个电梯的状态,一个电梯开们,关门,停,运行。每一种状态改变,都有可能要根据其他状态来更新处理。例如,开门状体,你不能在运行的时候开门,而是在电梯定下后才能开门。

例子2:我们给一部手机打电话,就可能出现这几种情况:用户开机,用户关机,用户欠费停机,用户消户等。 所以当我们拨打这个号码的时候:系统就要判断,该用户是否在开机且不忙状态,又或者是关机,欠费等状态。但不管是那种状态我们都应给出对应的处理操作。

基本概念

状态模式(State),当一个对象的内下状态改变时,允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。


环境类(Context):  定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。

抽象状态类(State):  定义一个接口以封装与Context的一个特定状态相关的行为。

具体状态类(ConcreteState):  每一子类实现一个与Context的一个状态相关的行为。

工作状态-状态模式版:



代码实现:

//抽象状态

#import "Work.h"

@interface State : NSObject

- (void)writeProgramWithWork:(Work *)work;// 工作

@end

// 上午工作状态

#import "ForenoonState.h"

#import "NoonState.h"

@implementation ForenoonState

- (void)writeProgramWithWork:(Work *)work

{

if (work.hour< 12) {

NSLog(@"当前时间为%zd 上午工作 精神百倍",work.hour);

}else{

NoonState *state = [[NoonState alloc] init];

[state writeProgramWithWork:work];

}

}

//中午状态

#import "NoonState.h"

#import "AfternoonState.h"

@implementation NoonState

- (void)writeProgramWithWork:(Work *)work

{

if (work.hour< 13) {

NSLog(@"当前时间为%zd 饿了 困了 吃饭 午休",work.hour);

}else{

AfternoonState *state = [[AfternoonState alloc] init];

[state writeProgramWithWork:work];

}

}

// 下午状态

#import "AfternoonState.h"

#import "EveningState.h"

@implementation AfternoonState

- (void)writeProgramWithWork:(Work *)work

{

if (work.hour< 17) {

NSLog(@"当前时间为%zd 下午状态还不错,继续努力",work.hour);

}else{

EveningState *state = [[EveningState alloc] init];

[state writeProgramWithWork:work];

}

}

@end

// 晚上状态

#import "EveningState.h"

#import "SleepingState.h"

#import "RestState.h"

@implementation EveningState

- (void)writeProgramWithWork:(Work *)work

{

if (work.finish) {// 如果任务完成就休息

RestState *state = [[RestState alloc] init];

[state writeProgramWithWork:work];

}else{

if (work.hour< 21) {

NSLog(@"当前时间为%zd 生活不易需要加班",work.hour);

}else{

SleepingState *state = [[SleepingState alloc] init];

[state writeProgramWithWork:work];

}

}

}

@end

// 睡觉状态

#import "SleepingState.h"

@implementation SleepingState

- (void)writeProgramWithWork:(Work *)work

{

NSLog(@"实在困的不行了,要好好的休息");

}

@end

// 下班休息状态

#import "RestState.h"

@implementation RestState

- (void)writeProgramWithWork:(Work *)work

{

NSLog(@"下班回家好好休息");

}

@end

// work类的实现

@class State;

@interface Work : NSObject

@property (nonatomic, strong)State *current;

@property (nonatomic, assign)int hour;

@property (nonatomic, assign)BOOL finish;

- (void)writeProgram;

@end

#import "Work.h"

#import "ForenoonState.h"

@implementation Work

- (instancetype)init

{

self = [super init];

if (self) {

self.current = [[ForenoonState alloc]init];

}

return self;

}

- (void)writeProgram

{

[self.current writeProgramWithWork:self];

}

@end

通过这个例子,可以看到,状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。

State模式有下面一些效果:

状态模式的优点:

1 ) 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来: State模式将所有与一个特定的状态相关的行为都放入一个对象中。因为所有与状态相关的代码都存在于某一个State子类中, 所以通过定义新的子类可以很容易的增加新的状态和转换。另一个方法是使用数据值定义内部状态并且让 Context操作来显式地检查这些数据。但这样将会使整个Context的实现中遍布看起来很相似的条件if else语句或switch case语句。增加一个新的状态可能需要改变若干个操作, 这就使得维护变得复杂了。State模式避免了这个问题, 但可能会引入另一个问题, 因为该模式将不同状态的行为分布在多个State子类中。这就增加了子类的数目,相对于单个类的实现来说不够紧凑。但是如果有许多状态时这样的分布实际上更好一些, 否则需要使用巨大的条件语句。正如很长的过程一样,巨大的条件语句是不受欢迎的。它们形成一大整块并且使得代码不够清晰,这又使得它们难以修改和扩展。 State模式提供了一个更好的方法来组织与特定状态相关的代码。决定状态转移的逻辑不在单块的 i f或s w i t c h语句中, 而是分布在State子类之间。将每一个状态转换和动作封装到一个类中,就把着眼点从执行状态提高到整个对象的状态。这将使代码结构化并使其意图更加清晰。

2) 它使得状态转换显式化: 当一个对象仅以内部数据值来定义当前状态时 , 其状态仅表现为对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得转换变得更加明确。而且, State对象可保证Context不会发生内部状态不一致的情况,因为从 Context的角度看,状态转换是原子的—只需重新绑定一个变量(即Context的State对象变量),而无需为多个变量赋值

3) State对象可被共享 如果State对象没有实例变量—即它们表示的状态完全以它们的类型来编码—那么各Context对象可以共享一个State对象。当状态以这种方式被共享时, 它们必然是没有内部状态, 只有行为的轻量级对象。

状态模式的缺点:

1) 状态模式的使用必然会增加系统类和对象的个数。

2) 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

具体实践联想:

在公司中有一个流程是课程的报名那么他会有多种状态,例如结束,开始,报名成功,报名成功和支付成功等,针对这些不同的状态具体的操作又不一样,同时还有包含的关系,例如开始报名的话,就需要报名,和支付两个状态同时出现,这个刚好进入的状态是开始报名,当报名成功后将状态变为报名成功,在调用报名成功状态下的方法,这样既可以将各个操作简单的写一次,也可以将各个操作分开处理,利于代码的梳理。

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

推荐阅读更多精彩内容