引言

我们在编程的时候,有时候会遇到,一个对象的行为动作会由对象的状态来决定的,也就是对象的行为是由状态来决定,如果对象的状态很多,那么也会由很多不同的行为,这时候我们一班会 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. Sublime Text:初学者不知道的那些事

    来源:Duchessjojo@译言 我是Sublime Text代码编辑器的忠实粉丝.我和诸多Mac程序员一样,最初使用的是Textmate代码编辑器.在Sublime Text 2发行后,我才开始转 ...

  2. mysql utf8方式连接查看表数据乱码的问题

    起因 今天在公司第一次链接一个新的mysql数据库,我看到在spring里配置的jdbc里datasource.url里有配置characterEncoding=utf8..然后就用navicat开选 ...

  3. Zabbix 源码编译安装

    简介: Zabbix 分布式监控系统,源码编译安装记录 ( 记不得是第多少次了 ) 下载地址:http://jaist.dl.sourceforge.net/project/zabbix/ZABBIX ...

  4. [iOS]UIScrollView左右拨动,第二页宽度只有一半问题

    用UIScrollView动态加入新View,而这个View是Xib方式创建,如果设置view的frame,这个view的宽度却只有设置的一半,很奇怪.于是我只设置view的frame的x值,不设置整 ...

  5. 封装basedao及动态创建新类型的java数组

    package com.huawei.base; import java.io.Serializable;import java.lang.reflect.Array;import java.lang ...

  6. Python实现七牛云视频播放

    这篇文章是使用Python的Web框架Django Rest Framework来提供视频相关的api接口,主要功能包括视频上传.视频转码.视频访问授权.删除视频文件.视频截图功能. 七牛云上的基本概 ...

  7. textarea文本域的高度随内容的变化而变化

    用css控制textarea文本域的高度随内容的变化而变化,不出现滚动条. CSS代码: 复制代码 代码如下: .t_area{ width:300px; overflow-y:visible } & ...

  8. Ajax 简单实例,其实就是js里面内容有些不同而已(转载)

    这些时间,瞎子也看得见,AJAX正大踏步的朝我们走来.不管我们是拥护也好,反对也罢,还是视而不见,AJAX像一阵潮流,席转了我们所有的人. 关于AJAX的定义也好,大话也好,早有人在网上发表了汗牛充栋 ...

  9. 28-Truck History(poj1789最小生成树)

    http://poj.org/problem?id=1789 Truck History Time Limit: 2000MS   Memory Limit: 65536K Total Submiss ...

  10. c/c++笔试面试试题

    C 试题(纯属转载) 1.求下面函数的返回值(微软) int func(x) {     int countx = 0;     while(x)     {           countx ++; ...