音效素材网提供各类素材,打造精品素材网站!

站内导航 站长工具 投稿中心 手机访问

音效素材

iOS App的设计模式开发中对State状态模式的运用
日期:2016-03-30 16:00:23   来源:脚本之家

1.概述

在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全都考虑到。然后使用if... ellse语句来做状态判断来进行不同情况的处理。但是对复杂状态的判断就显得“力不从心了”。随着增加新的状态或者修改一个状体(if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱。维护也会很麻烦。那么我就考虑只修改自身状态的模式。

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

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

2.问题

对象如何在每一种状态下表现出不同的行为?
3.解决方案

状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。

4.示例
先给出这个例子的类结构图。

2016330155229600.jpg (557×279)

上面的类结构图并不复杂,首先是抽象出一个状态的父类,通过工作类对时间点的设置来切换不同的状态。

逻辑结构并不复杂,还是给出简易的代码,大家可以慢慢体会一下。

注意:本文所有代码均在ARC环境下编译通过。

Work类接口

复制代码 代码如下:

#import <Foundation/Foundation.h>

@class State;
@interface Work :NSObject{
    State *current;
}
@property double Hour;
@property BOOL TaskFinished;
-(void)SetState:(State*)s;
-(void)WriteProgram;
@end


Work类实现
复制代码 代码如下:

#import "Work.h"
#import "State.h"
#import "ForenoonState.h"

@implementation Work
@synthesize Hour =_Hour;
@synthesize TaskFinished =_TaskFinished;

-(id)init{
    if (self == [superinit]) {
        current= [[ForenoonState    alloc]init];
    }
    return self;
}
-(void)SetState:(State *)s{
    current = s;
}
-(void)WriteProgram{
    [current WriteProgram:self];
}
@end


State类接口
复制代码 代码如下:

#import <Foundation/Foundation.h>

@class Work;
@interface State:NSObject
-(void)WriteProgram:(Work*)w;
@end


State类实现
复制代码 代码如下:

#import "State.h"
#import "Work.h"

@implementation State

-(void)WriteProgram:(Work *)w{
    NSLog(@"当前时间:%f点下班回家了",[w    Hour]);
}
@end


ForenoonState类接口
复制代码 代码如下:

#import    "State.h"

@interface    ForenoonState :State
@end


ForenoonState类实现
复制代码 代码如下:

#import "ForenoonState.h"
#import "Work.h"
#import "NoonState.h"

@implementation ForenoonState

-(void)WriteProgram:(Work *)w{
    if ([w Hour] < 12) {
        NSLog(@"当前时间:%f点上午工作,精神百倍", [w Hour]);
    }
    else {
        [w SetState:[NoonState new]];
        [w WriteProgram];
    }
}
@end


NoonState类接口
复制代码 代码如下:

#import "State.h"

@interface NoonState:State
@end


NoonState类实现
复制代码 代码如下:

#import "NoonState.h"
#import "Work.h"
#import "AfternoonState.h"

@implementation NoonState

-(void)WriteProgram:(Work *)w{
    if([w Hour] <13)
        NSLog(@"当前时间:%f点饿了,午饭;犯困,午休",[w Hour]);
    else {
        [w SetState:[[AfternoonState    alloc]init]];
        [w WriteProgram];
    }
}
@end


AfternoonState类接口
复制代码 代码如下:

#import "State.h"

@interface AfternoonState :State
@end


AfternoonState类实现
复制代码 代码如下:

#import "AfternoonState.h"
#import "Work.h"
#import "EveningState.h"

@implementation AfternoonState

-(void)WriteProgram:(Work *)w{
    if ([w Hour] <17) {
        NSLog(@"当前时间:%f点下午状态还不错,继续努力", [w Hour]);
    }
    else {
        [w SetState:[[EveningState alloc]init]];
        [w WriteProgram];
    }
}
@end


EveningState类接口
复制代码 代码如下:

#import "State.h"

@interface EveningState:State
@end


EveningState类实现
复制代码 代码如下:

#import "EveningState.h"
#import "Work.h"
#import "RestState.h"
#import "SleepingState.h"

@implementation EveningState

-(void)WriteProgram:(Work *)w{
    if ([w TaskFinished]) {
        [w SetState:[[RestState alloc]init]];
        [w WriteProgram];
    }
    else {
        if([w Hour] <21)
            NSLog(@"当前时间:%f点加班哦,疲惫之极", [w Hour]);
        else {
            [w SetState:[[SleepingState alloc]init]];
            [w WriteProgram];
        }
    }
}
@end


SleepingState类接口
复制代码 代码如下:

#import "State.h"

@interface SleepingState :State
@end


SleepingState类实现
复制代码 代码如下:

#import "SleepingState.h"
#import "Work.h"

@implementation SleepingState
-(void)WriteProgram:(Work *)w{
    NSLog(@"当前时间:%f点不行了,睡着了", [w Hour]);
}
@end


RestState类接口
复制代码 代码如下:

#import "RestState.h"
#import "Work.h"

@implementation RestState
-(void)WriteProgram:(Work *)w{
    NSLog(@"当前时间:%f点下班回家了", [w Hour]);
}
@end


Main方法调用
复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "Work.h"

int main (int argc,const char  *argv[])
{
    @autoreleasepool{
        Work *emergencyProjects = [[Work alloc]init];
        [emergencyProjects setHour:9];
        [emergencyProjects WriteProgram];
        [emergencyProjects setHour:10];
        [emergencyProjects WriteProgram];
        [emergencyProjects setHour:12];
        [emergencyProjects WriteProgram];
        [emergencyProjects setHour:13];
        [emergencyProjects WriteProgram];
        [emergencyProjects setHour:14];
        [emergencyProjects WriteProgram];
        [emergencyProjects setHour:17];
        [emergencyProjects WriteProgram];
        [emergencyProjects setTaskFinished:NO];
        [emergencyProjects setHour:19];
        [emergencyProjects WriteProgram];
        [emergencyProjects setHour:22];
        [emergencyProjects WriteProgram];
    }
    return 0;
}


上面是用Objective C语言实现的简单代码。

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

在下面的两种情况下均可使用State模式:
1) • 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
2) • 代码中包含大量与对象状态有关的条件语句:一个操作中含有庞大的多分支的条件(if else(或switch case)语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
6.结构

2016330155313791.jpg (594×265)

7.模式的组成

环境类(Context):  定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
抽象状态类(State):  定义一个接口以封装与Context的一个特定状态相关的行为。
具体状态类(ConcreteState):  每一子类实现一个与Context的一个状态相关的行为。
8.效果

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) 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

    您感兴趣的教程

    在docker中安装mysql详解

    本篇文章主要介绍了在docker中安装mysql详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编...

    详解 安装 docker mysql

    win10中文输入法仅在桌面显示怎么办?

    win10中文输入法仅在桌面显示怎么办?

    win10系统使用搜狗,QQ输入法只有在显示桌面的时候才出来,在使用其他程序输入框里面却只能输入字母数字,win10中...

    win10 中文输入法

    一分钟掌握linux系统目录结构

    这篇文章主要介绍了linux系统目录结构,通过结构图和多张表格了解linux系统目录结构,感兴趣的小伙伴们可以参考一...

    结构 目录 系统 linux

    PHP程序员玩转Linux系列 Linux和Windows安装

    这篇文章主要为大家详细介绍了PHP程序员玩转Linux系列文章,Linux和Windows安装nginx教程,具有一定的参考价值,感兴趣...

    玩转 程序员 安装 系列 PHP

    win10怎么安装杜比音效Doby V4.1 win10安装杜

    第四代杜比®家庭影院®技术包含了一整套协同工作的技术,让PC 发出清晰的环绕声同时第四代杜比家庭影院技术...

    win10杜比音效

    纯CSS实现iOS风格打开关闭选择框功能

    这篇文章主要介绍了纯CSS实现iOS风格打开关闭选择框,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作...

    css ios c

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的办法

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的

    Win7给电脑C盘扩容的办法大家知道吗?当系统分区C盘空间不足时,就需要给它扩容了,如果不管,C盘没有足够的空间...

    Win7 C盘 扩容

    百度推广竞品词的投放策略

    SEM是基于关键词搜索的营销活动。作为推广人员,我们所做的工作,就是打理成千上万的关键词,关注它们的质量度...

    百度推广 竞品词

    Visual Studio Code(vscode) git的使用教程

    这篇文章主要介绍了详解Visual Studio Code(vscode) git的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...

    教程 Studio Visual Code git

    七牛云储存创始人分享七牛的创立故事与

    这篇文章主要介绍了七牛云储存创始人分享七牛的创立故事与对Go语言的应用,七牛选用Go语言这门新兴的编程语言进行...

    七牛 Go语言

    Win10预览版Mobile 10547即将发布 9月19日上午

    微软副总裁Gabriel Aul的Twitter透露了 Win10 Mobile预览版10536即将发布,他表示该版本已进入内部慢速版阶段,发布时间目...

    Win10 预览版

    HTML标签meta总结,HTML5 head meta 属性整理

    移动前端开发中添加一些webkit专属的HTML5头部标签,帮助浏览器更好解析HTML代码,更好地将移动web前端页面表现出来...

    移动端html5模拟长按事件的实现方法

    这篇文章主要介绍了移动端html5模拟长按事件的实现方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家...

    移动端 html5 长按

    HTML常用meta大全(推荐)

    这篇文章主要介绍了HTML常用meta大全(推荐),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    cdr怎么把图片转换成位图? cdr图片转换为位图的教程

    cdr怎么把图片转换成位图? cdr图片转换为

    cdr怎么把图片转换成位图?cdr中插入的图片想要转换成位图,该怎么转换呢?下面我们就来看看cdr图片转换为位图的...

    cdr 图片 位图

    win10系统怎么录屏?win10系统自带录屏详细教程

    win10系统怎么录屏?win10系统自带录屏详细

    当我们是使用win10系统的时候,想要录制电脑上的画面,这时候有人会想到下个第三方软件,其实可以用电脑上的自带...

    win10 系统自带录屏 详细教程

    + 更多教程 +
    Windows系统Linux系统苹果MACAndroidiOS系统鸿蒙系统