引言

我们在编程的时候,有时候会遇到,一个对象的行为动作会由对象的状态来决定的,也就是对象的行为是由状态来决定,如果对象的状态很多,那么也会由很多不同的行为,这时候我们一班会 if –else if—来判断对象的行为,当对象的行为或者状态发生变化时,就需要更改之前的代码,这样的设计就违背了开闭原则,而状态模式就是用来解决这样的问题的

状态模式的介绍

  • 状态模式的定义

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像改变了其类

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把负责的判断逻辑简单化,如果这个状态判断很简单,就没毕业使用“状态模式”了。

  • 状态模式的结构图

  • 状态模式的组成

(1)、环境角色(Context):也称上下文,定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
    (2)、抽象状态角色(State):定义一个接口,用以封装环境对象的一个特定的状态所对应的行为。
    (3)、具体状态角色(ConcreteState):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

  • 状态模式的代码实现

比如:支付宝中蚂蚁会员等级来说明,分为:大众会员、黄金会员、铂金会员、钻石会员四种, 不同的等级享受的服务不同,我们就拿免费体现的额度来比较一下,钻石会员体现的额度是100万,其他都是2万的额度,感觉这差别太大了,当额度使用完以后,可以使用蚂蚁积分兑换,兑换的规则是 大众会员 1积分兑换1元体现额度,黄金会员1积分兑换1.5的额度,铂金1积分兑换3元,钻石1积分兑换5元

第一版

 class Program
{
static void Main(string[] args)
{
Member m = new Member();
m.Membership = "大众会员";
m.Lines = true;
m.Withdrawal();
m.Membership = "黄金会员";
m.Lines = false;
m.Withdrawal();
m.Membership = "铂金会员";
m.Lines = true;
m.Withdrawal();
m.Membership = "钻石会员";
m.Lines = true;
m.Withdrawal();
}
}
public class Member
{
public string Membership { get; set; } //会员等级
public bool Lines { get; set; } //免费体现额度 public void Withdrawal()
{
if (Membership=="大众会员")
{
if (Lines)
{
Console.WriteLine("大众会员1积分可以兑换1元提现额度");
}
else
{
Console.WriteLine("您还有免费的提现额度");
}
}
else if (Membership=="黄金会员")
{
if (Lines)
{
Console.WriteLine("黄金1积分可以兑换1.5元提现额度");
}
else
{
Console.WriteLine("您还有免费的提现额度");
}
}
else if (Membership=="铂金会员")
{
if (Lines)
{
Console.WriteLine("铂金会员1积分可以兑换3元提现额度");
}
else
{
Console.WriteLine("您还有免费的提现额度");
}
}
else
{
if (Lines)
{
Console.WriteLine("钻石1积分可以兑换5元提现额度");
}
else
{
Console.WriteLine("您有100的免费提现额度");
}
}
}
}

现在功能实现了,但是看仔细看看Member类中的Withdrawal方法,里面有很大分子判断,这就说明它的责任过大了,无论是任何状态,都需要通过它来改变,明显违背了“单一职责原则”、“开发封闭原则”。

第二版

    class Program
{
static void Main(string[] args)
{
Context m = new Context();
m.Action();
}
} public abstract class State
{
public abstract void Handle(Context context);
} public class PublicMember:State
{
public override void Handle(Context context)
{
if (context.Lines)
{
Console.WriteLine("大众会员1积分可以兑换1元提现额度");
}
else
{
Console.WriteLine("您还有免费的提现额度");
}
context.SetState(new GoldMember());
context.Lines = true;
context.Action();
}
} public class GoldMember:State
{
public override void Handle(Context context)
{
if (context.Lines)
{
Console.WriteLine("黄金1积分可以兑换1.5元提现额度");
}
else
{
Console.WriteLine("您还有免费的提现额度");
}
context.SetState(new PlatinumMember());
context.Lines = true;
context.Action();
}
} public class PlatinumMember : State
{
public override void Handle(Context context)
{
if (context.Lines)
{
Console.WriteLine("铂金会员1积分可以兑换3元提现额度");
}
else
{
Console.WriteLine("您还有免费的提现额度");
}
context.SetState(new DiamondMember());
context.Lines = true;
context.Action();
}
} public class DiamondMember : State
{
public override void Handle(Context context)
{
if (context.Lines)
{
Console.WriteLine("钻石1积分可以兑换5元提现额度");
}
else
{
Console.WriteLine("您有100的免费提现额度");
}
}
}
public class Context
{
public Context()
{
state = new PublicMember();
Lines = true;
}
private State state;
public string Membership { get; set; } //会员等级
public bool Lines { get; set; } //免费体现额度
public void SetState(State s)
{
state = s;
}
public void Action()
{
state.Handle(this);
}
}

状态模式的优缺点

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

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

总结

在对象的行动取决于本身的状态时,可以适用于状态模式,免去了过多的if–else判断,这对于一些复杂的和繁琐的判断逻辑有很好的帮助。但是使用状态模式,势必会造成更多的接口和类,对于非常简单的状态判断,可以不使用

c#设计模式系列:状态模式(State pattern)的更多相关文章

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

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

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

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

  3. [设计模式] 20 状态模式 State Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对状态模式是这样说的:允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类.状态模式的重点在于状态转换,很多时候,对 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Java使用 VelocityEngine模板引擎快速生成HTML等各种代码

    https://blog.csdn.net/icannotdebug/article/details/79725297 一.简介 Velocity 是一个基于 Java 的模板引擎框架,提供的模板语言 ...

  2. Linux下Spark框架配置(Python)

    简述  Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用并行框架,Spark,拥有Hadoop MapReduce所具有的优点:但不同于MapRedu ...

  3. Android自定义view与activity的传值

    昨晚在写团队项目的时候,遇到一个问题,直到今天早上才解决...即在自定义view"转盘"结束转动后获取结果的处理中,我是想吧值传到activity中的一个textview中的,但我 ...

  4. 高性能Web服务器Nginx的配置与部署研究(1)Nginx简介及入门示例

    概述 从这篇博文起,将带领读者们一起领略Nginx的强大. Nginx 是做什么用的?我相信很多朋友都已经使用过,如果你没有,那么你一定知道以下这些名称之一:Apache,Lighttpd,Tomca ...

  5. Hibernate中Session与本地线程绑定

    ------------------siwuxie095 Hibernate 中 Session 与本地线程绑定 1.Session 类似于 JDBC 的连接 Connection 2.Session ...

  6. 91. Decode Ways反编译字符串

    [抄题]: A message containing letters from A-Z is being encoded to numbers using the following mapping: ...

  7. $.ajax()函数

    一般在前端html和服务器交互,又要异步提交表单时,我们通常会用到$.ajax(){}函数,这是封装到ajax里的一个函数,相比于XMLHTTPRequest做页面局部刷新更方便,但最终还是使用的XM ...

  8. 1.spring.net Look-up Method 查找方法的注入(方法是抽象的需要spring.net注入)

    .为什么需要查找方法的注入 当Object依赖另一个生命周期不同的Object,尤其是当singleton依赖一个non-singleton时,常会遇到不少问题,Lookup Method Injec ...

  9. Android Touch 事件总结

    ---恢复内容开始--- 1.Touch事件传递机制 过程有点儿类似于栈, ViewGroup的子类有都继承它的以下3个方法: public boolean dispatchTouchEvent(Mo ...

  10. OSG图形设备接口GraphicsContext

    1.图形设备与相机 在Camera类的成员函数中,setGraphicContext()函数的工作是设置相机对应的图形设备对象,换句话说,下面要介绍的GraphicsContext类就是图形设备对象的 ...