一、 状态者(State)模式

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

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

二、 状态者模式的结构

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

从上图可知,状态者模式涉及以下三个角色:

  • Account类:维护一个State类的一个实例,该实例标识着当前对象的状态。
  • State类:抽象状态类,定义了一个具体状态类需要实现的行为约定。
  • SilveStater、GoldState和RedState类:具体状态类,实现抽象状态类的每个行为。

三、 状态者模式的实现

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

using System;

namespace StatePatternSample
{
public class Account
{
public State State { get; set; }
public string Owner { get; set; }
public Account(string owner)
{
this.Owner = owner;
this.State = new SilverState(0.0, this);
} public double Balance { get { return State.Balance; } } // 余额
// 存钱
public void Deposit(double amount)
{
State.Deposit(amount);
Console.WriteLine("存款金额为 {0:C}——", amount);
Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
Console.WriteLine("账户状态为: {0}", this.State.GetType().Name);
Console.WriteLine();
} // 取钱
public void Withdraw(double amount)
{
State.Withdraw(amount);
Console.WriteLine("取款金额为 {0:C}——", amount);
Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
Console.WriteLine("账户状态为: {0}", this.State.GetType().Name);
Console.WriteLine();
} // 获得利息
public void PayInterest()
{
State.PayInterest();
Console.WriteLine("Interest Paid --- ");
Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
Console.WriteLine("账户状态为: {0}", this.State.GetType().Name);
Console.WriteLine();
}
} // 抽象状态类
public abstract class State
{
// Properties
public Account Account { get; set; }
public double Balance { get; set; } // 余额
public double Interest { get; set; } // 利率
public double LowerLimit { get; set; } // 下限
public double UpperLimit { get; set; } // 上限 public abstract void Deposit(double amount); // 存款
public abstract void Withdraw(double amount); // 取钱
public abstract void PayInterest(); // 获得的利息
} // Red State意味着Account透支了
public class RedState : State
{
public RedState(State state)
{
// Initialize
this.Balance = state.Balance;
this.Account = state.Account;
Interest = 0.00;
LowerLimit = -100.00;
UpperLimit = 0.00;
} // 存款
public override void Deposit(double amount)
{
Balance += amount;
StateChangeCheck();
}
// 取钱
public override void Withdraw(double amount)
{
Console.WriteLine("没有钱可以取了!");
} public override void PayInterest()
{
// 没有利息
} private void StateChangeCheck()
{
if (Balance > UpperLimit)
{
Account.State = new SilverState(this);
}
}
} // Silver State意味着没有利息得
public class SilverState : State
{
public SilverState(State state)
: this(state.Balance, state.Account)
{
} public SilverState(double balance, Account account)
{
this.Balance = balance;
this.Account = account;
Interest = 0.00;
LowerLimit = 0.00;
UpperLimit = 1000.00;
} 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);
}
}
} // Gold State意味着有利息状态
public class GoldState : State
{
public GoldState(State state)
{
this.Balance = state.Balance;
this.Account = state.Account;
Interest = 0.05;
LowerLimit = 1000.00;
UpperLimit = 1000000.00;
}
// 存钱
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);
}
}
} class App
{
static void Main(string[] args)
{
// 开一个新的账户
var account = new Account("Learning Hard"); // 进行交易
// 存钱
account.Deposit(1000.0);
account.Deposit(200.0);
account.Deposit(600.0); // 付利息
account.PayInterest(); // 取钱
account.Withdraw(2000.00);
account.Withdraw(500.00); // 等待用户输入
Console.ReadKey();
}
}
}

上面代码的运行结果如下所示:

账户余额为 =:¥1,000.00
账户状态为:SilverState 存款金额为 ¥200.00——
账户余额为 =:¥1,200.00
账户状态为:GoldState 存款金额为 ¥600.00——
账户余额为 =:¥1,800.00
账户状态为:GoldState Interest Paid ---
账户余额为 =:¥1,890.00
账户状态为:GoldState 取款金额为 ¥2000.00——
账户余额为 =:¥-110.00
账户状态为:RedState 没有钱可以取了!
取款金额为 ¥500.00——
账户余额为 =:¥-110.00
账户状态为:RedState

从上面输出的内容可以发现,进行存取款交易,会影响到Account内部的状态,由于状态的改变,从而影响到Account类行为的改变,而且这些操作都是发生在运行时的。

四、 应用状态者模式完善中介者模式方案

我曾介绍到中介者模式存在的问题,下面利用观察者模式和状态者模式来完善中介者模式,具体的实现代码如下所示:

// 抽象牌友类

using System;
using System.Collections.Generic; public abstract class AbstractCardPartner
{
public int MoneyCount { get; set; } protected AbstractCardPartner()
{
MoneyCount = ;
} public abstract void ChangeCount(int count, AbstractMediator mediator);
} // 牌友A类
public class ParterA : AbstractCardPartner
{
// 依赖与抽象中介者对象
public override void ChangeCount(int count, AbstractMediator mediator)
{
mediator.ChangeCount(count);
}
} // 牌友B类
public class ParterB : AbstractCardPartner
{
// 依赖与抽象中介者对象
public override void ChangeCount(int count, AbstractMediator mediator)
{
mediator.ChangeCount(count);
}
} // 抽象状态类
public abstract class State
{
protected AbstractMediator Meditor;
public abstract void ChangeCount(int count);
} // A赢状态类
public class AWinState : State
{
public AWinState(AbstractMediator concretemediator)
{
this.Meditor = concretemediator;
} public override void ChangeCount(int count)
{
foreach (AbstractCardPartner p in Meditor.list)
{
var a = p as ParterA;
//
if (a != null)
{
a.MoneyCount += count;
}
else
{
p.MoneyCount -= count;
}
}
}
} // B赢状态类
public class BWinState : State
{
public BWinState(AbstractMediator concretemediator)
{
this.Meditor = concretemediator;
} public override void ChangeCount(int count)
{
foreach (AbstractCardPartner p in Meditor.list)
{
var b = p as ParterB;
// 如果集合对象中时B对象,则对B的钱添加
if (b != null)
{
b.MoneyCount += count;
}
else
{
p.MoneyCount -= count;
}
}
}
} // 初始化状态类
public class InitState : State
{
public InitState()
{
Console.WriteLine("游戏才刚刚开始,暂时还有玩家胜出");
} public override void ChangeCount(int count)
{
//
return;
}
} // 抽象中介者类
public abstract class AbstractMediator
{
public List<AbstractCardPartner> list = new List<AbstractCardPartner>(); public State State { get; set; } protected AbstractMediator(State state)
{
this.State = state;
} public void Enter(AbstractCardPartner partner)
{
list.Add(partner);
} public void Exit(AbstractCardPartner partner)
{
list.Remove(partner);
} public void ChangeCount(int count)
{
State.ChangeCount(count);
}
} // 具体中介者类
public class MediatorPater : AbstractMediator
{
public MediatorPater(State initState)
: base(initState)
{ }
} class Program
{
static void Main(string[] args)
{
AbstractCardPartner a = new ParterA();
AbstractCardPartner b = new ParterB();
// 初始钱
a.MoneyCount = ;
b.MoneyCount = ; AbstractMediator mediator = new MediatorPater(new InitState()); // A,B玩家进入平台进行游戏
mediator.Enter(a);
mediator.Enter(b); // A赢了
mediator.State = new AWinState(mediator);
mediator.ChangeCount();
Console.WriteLine("A 现在的钱是:{0}", a.MoneyCount);// 应该是25
Console.WriteLine("B 现在的钱是:{0}", b.MoneyCount); // 应该是15 // B 赢了
mediator.State = new BWinState(mediator);
mediator.ChangeCount();
Console.WriteLine("A 现在的钱是:{0}", a.MoneyCount);// 应该是25
Console.WriteLine("B 现在的钱是:{0}", b.MoneyCount); // 应该是15
Console.Read();
}
}

五、 状态者模式的应用场景

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

  1. 当一个对象状态转换的条件表达式过于复杂时可以使用状态者模式。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化。
  2. 当一个对象行为取决于它的状态,并且它需要在运行时刻根据状态改变它的行为时,就可以考虑使用状态者模式。

六、 状态者模式的优缺点

优点:

  1. 将状态判断逻辑每个状态类里面,可以简化判断的逻辑。
  2. 当有新的状态出现时,可以通过添加新的状态类来进行扩展,扩展性好。

缺点:

  1. 如果状态过多的话,会导致有非常多的状态类,加大了开销。

七、 总结

状态者模式是对对象状态的抽象,从而把对象中对状态复杂的判断逻辑已到各个状态类里面,从而简化逻辑判断。

C#设计模式-状态者模式的更多相关文章

  1. C#设计模式:状态者模式(State Pattern)

    一,什么是状态设计模式? 1,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 2,当一个对象的内部状态改变时允许改变其行为,这个对象看起来像是 ...

  2. C#设计模式(19)——状态者模式(State Pattern)

    一.引言 在上一篇文章介绍到可以使用状态者模式和观察者模式来解决中介者模式存在的问题,在本文中将首先通过一个银行账户的例子来解释状态者模式,通过这个例子使大家可以对状态者模式有一个清楚的认识,接着,再 ...

  3. .NET设计模式访问者模式

    一.访问者模式的定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 二.访问者模式的结构和角色: 1.Visitor 抽象访问者角色,为该 ...

  4. [Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  5. [Head First设计模式]抢票中的设计模式——代理模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  6. [Head First设计模式]策略模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  7. [Head First设计模式]餐馆中的设计模式——命令模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  8. [Head First设计模式]生活中学设计模式——迭代器模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  9. [Head First设计模式]生活中学设计模式——组合模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

随机推荐

  1. 干货分享:SQLSERVER使用裸设备

    干货分享:SQLSERVER使用裸设备 这篇文章也适合ORACLE DBA和MYSQL DBA 阅读 裸设备适用于Linux和Windows 在ORACLE和MYSQL里也是支持裸设备的!! 介绍 大 ...

  2. Asp.net MVC 传递数据 从前台到后台,包括单个对象,多个对象,集合

    今天为大家分享下 Asp.net MVC 将数据从前台传递到后台的几种方式. 环境:VS2013,MVC5.0框架 1.基本数据类型 我们常见有传递 int, string, bool, double ...

  3. 怎么让网站在本地支持SSL?

    打开vs,点击项目,查看属性,打开ssl 如果有什么危险提示,就允许 右击项目,选择属性 运行项目

  4. CentOS7 重置root密码

    1- 在启动grub菜单,选择编辑选项启动 2 - 按键盘e键,来进入编辑界面 3 - 找到Linux 16的那一行,将ro改为rw init=/sysroot/bin/sh 4 - 现在按下 Con ...

  5. 如果你也会C#,那不妨了解下F#(7):面向对象编程之继承、接口和泛型

    前言 面向对象三大基本特性:封装.继承.多态.上一篇中介绍了类的定义,下面就了解下F#中继承和多态的使用吧.

  6. 企业做数据缓存是使用Memcached还是选Redis?

    企业是使用Memcached还是选Redis? 在构建一款现代且由数据库驱动的Web应用程序并希望使其拥有更为出色的性能表现时,这个问题总会时不时出现.并给每一位开发人员带来困扰.在考虑对应用程序的性 ...

  7. 前端开发小白必学技能—非关系数据库又像关系数据库的MongoDB快速入门命令(2)

    今天给大家道个歉,没有及时更新MongoDB快速入门的下篇,最近有点小忙,在此向博友们致歉.下面我将简单地说一下mongdb的一些基本命令以及我们日常开发过程中的一些问题.mongodb可以为我们提供 ...

  8. 性能测试工具 wrk 安装与使用

    介绍 今天给大家介绍一款开源的性能测试工具 wrk,简单易用,没有Load Runner那么复杂,他和 apache benchmark(ab)同属于性能测试工具,但是比 ab 功能更加强大,并且可以 ...

  9. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  10. 电商系统中的商品模型的分析与设计—续

    前言     在<电商系统中的商品模型的分析与设计>中,对电商系统商品模型有一个粗浅的描述,后来有博友对货品和商品的区别以及属性有一些疑问.我也对此做一些研究,再次简单的对商品模型做一个介 ...