状态者模式的介绍

  每个对象都有其对应的状态,而每个状态又对应一些相应的行为,如果某个对象有多个状态时,那么就会对应很多的行为。那么对这些状态的判断和根据状态完成的行为,就会导致多重条件语句,并且如果添加一种新的状态时,需要更改之前现有的代码。这样的设计显然违背了开闭原则。状态模式正是用来解决这样的问题的。状态模式将每种状态对应的行为抽象出来成为单独新的对象,这样状态的变化不再依赖于对象内部的行为。

状态者模式的定义

  上面对状态模式做了一个简单的介绍,这里给出状态模式的定义。

  状态模式——允许一个对象在其内部状态改变时自动改变其行为,对象看起来就像是改变了它的类。

状态者模式的结构

  既然状态者模式是对已有对象的状态进行抽象,则自然就有抽象状态者类和具体状态者类,而原来已有对象需要保存抽象状态者类的引用,通过调用抽象状态者的行为来改变已有对象的行为。经过上面的分析,状态者模式的结构图也就很容易理解了,具体结构图如下图示。

  • State----抽象状态角色
          接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。 
  • ConcreteState----具体状态角色
          本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。 
  • Context----环境角色
          定义客户端需要的接口,并且负责具体状态的切换。
 
    环境角色有两个不成文的约束:    
  • 把状态对象声明为静态常量,有几个状态对象就声明几个静态常量。
  • 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。
 
具体代码实现:

namespace ConsoleApplication1
{
/// <summary>
/// 抽象状态角色
/// </summary>
public abstract class State
{
//定义一个环境角色,提供子类访问
protected Context context;
public Context Context
{
set { context = value; }
}
//行为1
public abstract void handle1();
//行为2
public abstract void handle2();
}
/// <summary>
/// 具体状态角色
/// </summary>
public class ConcreteState1 : State
{
public override void handle1()
{
//本状态下必须处理的逻辑
}
public override void handle2()
{
//设置当前状态为state2
context.CurrentState = Context.STATE2;
//过渡到state2状态,由Context实现
context.handle2();
}
}
/// <summary>
/// 具体状态角色
/// </summary>
public class ConcreteState2 : State
{
public override void handle1()
{
//设置当前状态为state1
context.CurrentState = Context.STATE1;
//过渡到state1状态,由Context实现
context.handle1();
}
public override void handle2()
{
//本状态下必须处理的逻辑
}
}
/// <summary>
/// 具体环境角色
/// </summary>
public class Context
{
//定义状态
public static State STATE1 = new ConcreteState1();
public static State STATE2 = new ConcreteState2();
//当前状态
private State currentState;
public State CurrentState
{
get
{
//获取当前状态
return currentState;
}
set
{
//设置当前状态
currentState=value;
currentState.Context=this;
}
}
//行为委托
public void handle1()
{
currentState.handle1();
}
public void handle2()
{
currentState.handle2();
}
}
class Program
{
static void Main(string[] args)
{
//定义环境角色
Context context = new Context();
//初始化状态
context.CurrentState = new ConcreteState1();
//行为执行
context.handle1();
context.handle2();
Console.ReadLine();
}
}
}

状态者模式的优缺点

  状态者模式的主要优点是:

  • 结构清晰
          避免了过多的switch...case或者if...else语句使用,避免了程序的复杂性,提高系统的可维护性。 
  • 遵循设计原则
          很好的体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。 
  • 封装性非常好
          状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
 

  状态者模式的主要缺点是:

  • 子类会太多,也就是类膨胀。

状态者模式的应用场景

  在以下情况下可以考虑使用状态者模式。

  • 行为随状态改变而改变的场景
  • 条件、分组判断语句的替代者
          在程序中大量使用switch语句或者if判断语句会导致程序结构不清晰,逻辑混乱,使用状态模式可以很好地避免这一问题,它通过扩展子类 实现了条件的判断处理。

应用一:

用状态模式来模拟一个电梯的状态场景:

具体代码实现:

namespace ConsoleApplication1
{
/// <summary>
/// 抽象电梯状态
/// </summary>
public abstract class LiftState
{
protected Context context;
public Context Context
{
set { context = value; }
}
//首先电梯们开启动作
public abstract void open();
//电梯们有开启,那当然也就有关闭了
public abstract void close();
//电梯要能上能下,运行起来
public abstract void run();
//电梯还要能停下来
public abstract void stop();
} /// <summary>
/// 敞门状态
/// </summary>
public class OpenningState : LiftState
{
//打开电梯门
public override void open()
{
Console.WriteLine("电梯门开启...");
} public override void close()
{
context.LiftState = Context.closeingState;
context.LiftState.close();
} public override void run()
{ } public override void stop()
{ }
} /// <summary>
/// 关闭状态
/// </summary>
public class CloseingState : LiftState
{
//电梯门关了再打开
public override void open()
{
//设置为敞门状态
context.LiftState = Context.openningState;
context.LiftState.open();
} //电梯门关闭,这是关闭状态要实现的动作
public override void close()
{
Console.WriteLine("电梯门关闭...");
}
//电梯门关了就运行
public override void run()
{
//设置为运行状态
context.LiftState = Context.runingState;
context.LiftState.run();
}
//电梯门关着
public override void stop()
{
//设置为停止状态
context.LiftState = Context.stoppingState;
context.LiftState.stop();
}
} /// <summary>
/// 运行状态
/// </summary>
public class RunningSate : LiftState
{ public override void open()
{ } public override void close()
{ } public override void run()
{
Console.WriteLine("电梯上下运行...");
} public override void stop()
{
//设置为停止状态
context.LiftState = Context.stoppingState;
context.LiftState.stop();
}
} /// <summary>
/// 停止状态
/// </summary>
public class StoppingState : LiftState
{ public override void open()
{
//设置为敞门状态
context.LiftState = Context.openningState;
context.LiftState.open();
} public override void close()
{ } public override void run()
{
//设置为运行状态
context.LiftState = Context.runingState;
context.LiftState.run();
} public override void stop()
{
Console.WriteLine("电梯停止了...");
}
} /// <summary>
/// 上下文类
/// </summary>
public class Context
{
//定义出所有的电梯状态
public static OpenningState openningState = new OpenningState();
public static CloseingState closeingState = new CloseingState();
public static RunningSate runingState = new RunningSate();
public static StoppingState stoppingState = new StoppingState(); //定义一个当前电梯状态
private LiftState liftState;
public LiftState LiftState
{
get
{
return liftState;
}
set
{
liftState = value;
//把当前的环境通知到各个实现类中
liftState.Context = this;
}
} public void open()
{
liftState.open();
} public void close()
{
liftState.close();
} public void run()
{
liftState.run();
} public void stop()
{
liftState.stop();
}
} class Program
{
static void Main(string[] args)
{
Context context = new Context();
context.LiftState = new CloseingState();
context.open();
context.close();
context.run();
context.stop();
Console.ReadLine();
}
}
}

应用二:

下面,就以银行账户的状态来实现下状态者模式。银行账户根据余额可分为RedState、SilverState和GoldState。这些状态分别代表透支账号,新开账户和标准账户。账号余额在【-100.0,0.0】范围表示处于RedState状态,账号余额在【0.0 , 1000.0】范围表示处于SilverState,账号在【1000.0, 100000.0】范围表示处于GoldState状态。下面以这样的一个场景实现下状态者模式,具体实现代码如下所示:

namespace ConsoleApplication1
{
/// <summary>
/// 抽象存款状态
/// </summary>
public abstract class State
{
protected Account context;
public Account Context
{
set { context = value; }
} /// <summary>
/// 余额
/// </summary
public double Balance { get; set; }
/// <summary>
/// 利率
/// </summary>
public double Interest { get; set; }
/// <summary>
/// 下限
/// </summary>
public double LowerLimit { get; set; }
/// <summary>
/// 上限
/// </summary>
public double UpperLimit { get; set; } public abstract void Deposit(double amount); // 存款
public abstract void Withdraw(double amount); // 取钱
public abstract void PayInterest(); // 获得的利息 public void Display(string OperationType, double amount)
{
switch (OperationType)
{
case "Deposit":
Console.WriteLine("存款金额为 {0:C}——", amount);
Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
Console.WriteLine("账户状态为: {0}", this.GetType().Name);
Console.WriteLine();
break;
case "Withdraw":
Console.WriteLine("取款金额为 {0:C}——", amount);
Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
Console.WriteLine("账户状态为: {0}", this.GetType().Name);
Console.WriteLine();
break;
case "PayInterest":
Console.WriteLine("Interest Paid --- ");
Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
Console.WriteLine("账户状态为: {0}", this.GetType().Name);
Console.WriteLine();
break;
default:
break;
}
} } /// <summary>
/// Red State意味着Account透支
/// </summary>
public class RedState : State
{ public RedState()
{
Interest = 0.00;
LowerLimit = -100.00;
UpperLimit = 0.00;
} public RedState(double balance)
:this()
{
this.Balance = balance;
} // 存款
public override void Deposit(double amount)
{
Balance += amount;
if (Balance > UpperLimit)
{
context.AccountState = new SilverState(this.Balance); //Context.silverState;
}
} // 取钱
public override void Withdraw(double amount)
{
Console.WriteLine("没有钱可以取了!");
} public override void PayInterest()
{
// 没有利息
}
} /// <summary>
/// Silver State意味着没有利息得
/// </summary>
public class SilverState : State
{
public SilverState()
{
Interest = 0.00;
LowerLimit = 0.00;
UpperLimit = 1000.00;
} public SilverState(double balance)
:this()
{
this.Balance = balance;
} public override void Deposit(double amount)
{
Balance += amount;
StateChangeCheck();
} public override void Withdraw(double amount)
{
Balance -= amount;
StateChangeCheck();
} public override void PayInterest()
{
Balance += Interest * Balance;
StateChangeCheck();
} private void StateChangeCheck()
{
if (Balance < LowerLimit)
{
context.AccountState = new RedState(this.Balance);//Context.redState;
}
else if (Balance > UpperLimit)
{
context.AccountState = new GoldState(this.Balance);//Context.goldState;
}
}
} /// <summary>
/// Gold State意味着有利息状态
/// </summary>
public class GoldState : State
{ public GoldState()
{
Interest = 0.05;
LowerLimit = 1000.00;
UpperLimit = 1000000.00;
} public GoldState(double balance)
:this()
{
this.Balance = balance;
} public override void Deposit(double amount)
{
Balance += amount;
StateChangeCheck();
} public override void Withdraw(double amount)
{
Balance -= amount;
StateChangeCheck();
} public override void PayInterest()
{
Balance += Interest * Balance;
StateChangeCheck();
} private void StateChangeCheck()
{
if (Balance < 0.0)
{
context.AccountState = new RedState(this.Balance);//Context.redState;
}
else if (Balance < LowerLimit)
{
context.AccountState = new SilverState(this.Balance);//Context.silverState;
}
} } /// <summary>
/// 上下文类
/// </summary>
public class Account
{
//定义出所有的存款账户状态
//public static RedState redState = new RedState();
//public static SilverState silverState = new SilverState();
//public static GoldState goldState = new GoldState(); //定义一个当前存款账户状态
private State accountState;
public State AccountState
{
get
{
return accountState;
}
set
{
accountState = value;
//把当前的环境通知到各个实现类中
accountState.Context = this;
}
} public void Deposit(double amount)
{
accountState.Deposit(amount);
accountState.Display("Deposit", amount);
} public void Withdraw(double amount)
{
accountState.Withdraw(amount);
accountState.Display("Withdraw", amount);
} public void PayInterest()
{
accountState.PayInterest();
accountState.Display("PayInterest", );
}
} class Program
{
static void Main(string[] args)
{
Account account = new Account();
account.AccountState = new SilverState(0.0); // 进行交易
// 存钱
account.Deposit(1000.0);
account.Deposit(200.0);
account.Deposit(600.0); // 付利息
account.PayInterest(); // 取钱
account.Withdraw(2000.00);
account.Withdraw(500.00); Console.ReadLine();
}
}
}

行为型---状态者模式(State Pattern)的更多相关文章

  1. 19.状态者模式(State Pattern)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. 二十四种设计模式:状态模式(State Pattern)

    状态模式(State Pattern) 介绍允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它所属的类. 示例有一个Message实体类,对它的操作有Insert()和Get()方法, ...

  3. 乐在其中设计模式(C#) - 状态模式(State Pattern)

    原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...

  4. 状态模式-State Pattern(Java实现)

    状态模式-State Pattern 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. State接口 ...

  5. 【UE4 设计模式】状态模式 State Pattern

    概述 描述 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类. 其别名为状态对象(Objects for States),状态模式是一种对象行为型模式. 有限状态机(FSMs) ...

  6. 设计模式(十二):通过ATM取款机来认识“状态模式”(State Pattern)

    说到状态模式,如果你看过之前发布的重构系列的文章中的<代码重构(六):代码重构完整案例>这篇博客的话,那么你应该对“状态模式”并不陌生,因为我们之前使用到了状态模式进行重构.上一篇博客我们 ...

  7. 十一个行为模式之状态模式(State Pattern)

    定义: 当一个对象有多个状态,并且在每个状态下有不同的行为,可以使用状态模式来在其内部改变状态时改变其行为,而客户端不会察觉状态的改变,仍使用同样的方法或接口与对象进行交互. 结构图: Context ...

  8. php状态模式(state pattern)

    ... <?php /* The state pattern encapsulates the varying behavior for the same object based on its ...

  9. 状态模式(State Pattern)

    当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂 ...

随机推荐

  1. Sql- Group By ,Where,having用法

    Group by,where,having 是数据库查询中最常用的几个关键字.在工作中,时常用到,前面遇到一个问题,一个查询中使用了where ,group by ,having及聚集函数时 ,执行顺 ...

  2. FreeRTOS学习目录

    1.关于实时操作系统的一些概念性问题 2.freeRTOS与裸机程序相比有什么区别?? 3.freeRTOSConfig.h文件对FreeRTOS进行系统配置 4.FreeRTOS的内存管理

  3. 软件测试-chapter2-homework2

    程序一 1.the fault:for循环中i>0应改为i>=0 for (int i=x.length-1; i >= 0; i--) 2. (Reachability可达性,是f ...

  4. shell 命令 创建/删除 软连接 ln -s

    软链接的作用是, 1. 节省复制造成的空间浪费 2. 保证两个文件的内容同时修改 所以,可以把软连接理解为给文件/文件夹创建了别名,当访问别名时,实际访问的是链接的文件/文件夹 软链文件 ln -s ...

  5. SSD硬盘安装win10 且安装千牛工作台频繁卡死问题解决过程

    之前win7的时候突然出现卡死现象,具体表现为:磁盘占用百分之百,千牛窗口无法关闭,点截图按钮后,千牛关闭了,并没有截图,千牛聊天输入/无法出现快捷短语了,电脑桌面点击右键没反应,任务栏点击右键也没反 ...

  6. 搭建vue环境

    1. 下载安装nodejs 截至2018-06-05 最新稳定版本为 8.11.2,直接 next ,不改目录. PS C:\Users\Administrator> node -v v8.11 ...

  7. 在使用可变数组过程中遇到*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'问题

    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFD ...

  8. 我的C++ 学习心得

    创建这个博客已经是我大一下学期的暑假了,这一年里,我学习了人生第一门编程语言C++ . C++是一门当前仍然活跃于开发前沿的编程语言.在还未开始正式学习它时,早就听到我们的学长抱怨C++难学.起初,我 ...

  9. 目标检测算法(1)目标检测中的问题描述和R-CNN算法

    目标检测(object detection)是计算机视觉中非常具有挑战性的一项工作,一方面它是其他很多后续视觉任务的基础,另一方面目标检测不仅需要预测区域,还要进行分类,因此问题更加复杂.最近的5年使 ...

  10. [Postman]发送第一个请求(1)

    通过API请求,您可以与具有要访问的API端点的服务器联系,并执行某些操作.这些操作是HTTP方法. 最常用的方法是GET,POST,PUT和DELETE.方法的名称是不言自明的.例如,GET使您可以 ...