一、定义

定义:允许对象在内部状态改变时改变它的行为, 对象看起来好像修改了它的类。

主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

何时使用:代码中包含大量与对象状态有关的条件语句。

如何解决:将各种具体的状态类抽象出来。

关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。

二、结构图

Context类:维护一个ConcreteState子类的一个实例,这个实例定义当前的状态。

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

ConcreteStateA,ConcreteStateB,ConcreteStateC类:具体状态类,每一个子类实现一个与Context的一个状态相关的行为。

三、适用场景

1、行为随状态改变而改变的场景。

2、条件、分支语句的代替者。

四、优缺点

优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点: 1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

五、实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DesignPatterns.StatePattern
{
class Program
{
static void Main(string[] args)
{
// Open a new account
Account account = new Account("Jim Johnson");
// Apply financial transactions
account.Deposit(500.0);
account.Deposit(300.0);
account.Deposit(550.0);
account.PayInterest();
account.Withdraw(2000.00);
account.Withdraw(1100.00);
// Wait for user
Console.ReadKey();
}
} class Account
{
private State _state;
private string _owner;
// Constructor
public Account(string owner)
{
// New accounts are 'Silver' by default
this._owner = owner; this._state = new SilverState(0.0, this);
} // Properties
public double Balance
{
get { return _state.Balance; }
}
public State State
{
get { return _state; }
set { _state = value; }
}
public void Deposit(double amount)
{
_state.Deposit(amount);
Console.WriteLine("Deposited {0:C} --- ", amount);
Console.WriteLine("Balance = {0:C}", this.Balance);
Console.WriteLine("Status = {0}",this.State.GetType().Name);
Console.WriteLine("");
}
public void Withdraw(double amount)
{
_state.Withdraw(amount);
Console.WriteLine("Withdrew {0:C} --- ", amount);
Console.WriteLine(" Balance = {0:C}", this.Balance);
Console.WriteLine(" Status = {0}\n",
this.State.GetType().Name);
} public void PayInterest()
{
_state.PayInterest();
Console.WriteLine("Interest Paid --- ");
Console.WriteLine(" Balance = {0:C}", this.Balance);
Console.WriteLine(" Status = {0}\n",
this.State.GetType().Name);
}
} /// <summary>
/// The 'State' abstract class
/// </summary>
abstract class State
{
protected Account account;
protected double balance;
protected double interest;
protected double lowerLimit;
protected double upperLimit; // Properties
public Account Account
{
get { return account; }
set { account = value; }
}
public double Balance
{
get { return balance; }
set { balance = value; }
}
public abstract void Deposit(double amount);
public abstract void Withdraw(double amount);
public abstract void PayInterest(); } /// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Red indicates that account is overdrawn
/// </remarks>
/// </summary>
class RedState : State
{
private double _serviceFee;
// Constructor
public RedState(State state)
{
this.balance = state.Balance;
this.account = state.Account;
Initialize();
}
private void Initialize()
{
// Should come from a datasource
interest = 0.0;
lowerLimit = -100.0;
upperLimit = 0.0;
_serviceFee = 15.00;
} public override void Deposit(double amount)
{
balance += amount;
StateChangeCheck();
} public override void Withdraw(double amount)
{
amount = amount - _serviceFee;
Console.WriteLine("No funds available for withdrawal!");
} public override void PayInterest()
{
// No interest is paid
} private void StateChangeCheck()
{
if (balance > upperLimit)
{
account.State = new SilverState(this);
}
}
}
/// <summary> /// A 'ConcreteState' class
/// <remarks>
/// Silver indicates a non-interest bearing state
/// </remarks>
/// </summary>
class SilverState : State
{
// Overloaded constructors
public SilverState(State state)
:
this(state.Balance, state.Account)
{ }
public SilverState(double balance, Account account)
{
this.balance = balance;
this.account = account;
Initialize();
} private void Initialize()
{
// Should come from a datasource
interest = 0.0;
lowerLimit = 0.0;
upperLimit = 1000.0;
} 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)
{
account.State = new RedState(this);
}
else if (balance > upperLimit)
{
account.State = new GoldState(this);
}
}
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Gold indicates an interest bearing state
/// </remarks>
/// </summary>
class GoldState : State
{
// Overloaded constructors
public GoldState(State state)
: this(state.Balance, state.Account)
{
}
public GoldState(double balance, Account account)
{
this.balance = balance;
this.account = account;
Initialize();
}
private void Initialize()
{
// Should come from a database
interest = 0.05;
lowerLimit = 1000.0;
upperLimit = 10000000.0;
}
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)
{
account.State = new RedState(this);
}
else if (balance < lowerLimit)
{
account.State = new SilverState(this);
}
}
}
}

现实中还有其他很多例子,比如自动贩卖机、电梯等。

状态模式的关键在于 状态变化时引起行为的变化,它是被动的触发

策略模式的差别在于,它是由外部(client)主动引起行为的变化,可以随意控制它想要执行的行为。

参考文章:

http://www.cnblogs.com/ywqu/archive/2010/01/26/1656418.html

http://www.runoob.com/design-pattern/state-pattern.html

http://www.cnblogs.com/JsonShare/p/7246915.html

欢迎阅读本系列文章:Head First设计模式之目录

Head First设计模式之状态模式的更多相关文章

  1. 【转】设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  2. 设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

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

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

  4. 折腾Java设计模式之状态模式

    原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...

  5. 北风设计模式课程---状态模式State(对象行为型)

    北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...

  6. js设计模式——5.状态模式

    js设计模式——5.状态模式 代码演示 /*js设计模式——状态模式*/ // 状态(红灯,黄灯,绿灯) class State { constructor(color) { this.color = ...

  7. 设计模式2——状态模式State

    参考链接: 设计模式之状态模式:https://www.cnblogs.com/haoerlv/p/7777789.html 设计模式系列之状态模式:https://www.jianshu.com/p ...

  8. python设计模式之状态模式

    python设计模式之状态模式 面向对象编程着力于在对象交互时改变它们的状态.在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具.首先,什么是状态 ...

  9. Head First 设计模式 --10 状态模式

    状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了他的类. 用到的设计原则1.封装变化2.多用组合,少用继承3.针对接口编程,不针对实现编程4.松耦合5.对扩展开放,对修改关闭6.依 ...

  10. 设计模式之 -- 状态模式(State)

     状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类.当控制一个对象的状态转换条件分支语句(if...else或switch...case)过于复杂时,可以此模式将状态的判断逻辑 ...

随机推荐

  1. php+jQuery+Mysql找回密码----ThinkPHP

    最近用ThinkPHP做了一个邮箱找回密码功能,在遭遇了N个bug之后终于做成了,下面分享一下邮箱找回密码功能的实现: 邮箱找回密码实际上就是在用户通过验证之后重置密码的过程,一般开发者会在验证用户信 ...

  2. Java二分法

    public class Dichotomy {        //定义查找次数    static int count = 0;        public static void main(Str ...

  3. NGUI_Input

    九.输入框Input 1.凡是用户可以输入文本的地方,几乎都用输入框,有登录账号和密码.输入角色名称.输入聊天内容 2.手动拼接输入框,拖动预制体的就不再说了 (1).创建一个Sprite作为输入框的 ...

  4. Abp扩展之【配置功能】

    Abp的扩展功能非常强大,配合持久化可以很方便的配置系统.租户.用户的配置,关于ABP的配置请参考: http://www.cnblogs.com/farb/p/ABPSettingManagemen ...

  5. Web离线应用解决方案——ServiceWorker

    什么是ServiceWorker 在介绍ServiceWorker之前,我们先来谈谈PWA.PWA (Progressive Web Apps) 是一种 Web App 新模型,并不是具体指某一种前沿 ...

  6. form表单参数传递和url参数传递的区别

    template: form表单: <form action="" method='GET'> <div class="input-group" ...

  7. window.open()被拦截问题

    最近做项目的时候遇到一个需求,在商品详情页面中点击购买按钮,之后再新标签页中打开生成的订单页面,所以想用window.open()来实现.但是测试的时候发现打开的链接被浏览器拦截. 之后,开始在网上查 ...

  8. js onmouseover与onmouseout用法

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  9. Dynamic HTML权威指南(读书笔记)— 第一章 HTML与XHTML参考

    1. 对齐常量(text-align和vertical-align) 1.1 盒外对齐 这种对齐属性决定环绕着元素外部矩形空间的文本对齐方式.W3C中,这类HTML元素包括:applet.iframe ...

  10. 经常使用的C#代码(每日更新)

    欢迎使用该软件,软件中包括了经常使用的代码.而且每日更新. 该软件还在开发中,O(∩_∩)O~ 目的: 1.提高工作效率 2.格式化代码,方便阅读 3.必备工具 4.偷懒专用 watermark/2/ ...