用依赖注入和代理模式实现状态模式

stateful对象的关注点

对象状态的确定

 状态是由对象的一个和多个属性决定的,复杂情况下对象的状态是由对象的多个属性根据算法计算获得的

对象状态的变化

 当决定状态的属性变化的时候,对象的状态会发生变化

对象状态对行为的约束

 对象可以有多个行为,比如method1(),method2(),method3()。
 对象的行为受到状态的约束,比如在对象在state1 下,只能做method1的操作,在state2下只能做method2,method3的操作

传统的对stateful对象的实现

缺点:

  1. 确定某个状态拥有哪些行为需要大量的分支语句(if-else or switch)
  2. 当增加状态或者行为的时候,需要修改大量代码。

经典的状态模式

代码实例:

网上有很多优秀的实例,可以参照http://blog.csdn.net/hguisu/article/details/7557252

优点:

 1. 把状态和状态对行为的约束从对象的代码中抽离出来放到独立的状态类中。
 2. 对象类专注行为,对象的状态类专注于对行为的约束

依赖注入和动态代理实现的状态模式

案例背景

以一个考生面试系统的考场对象为例子

  1. 考场有 3个状态(Preparing,Ongoing,Finish)
  2. 考场有多个行为 2.1 为考场初始化考官 2.2 考场导入考生 2.3 开始1个考生的面试 2.4 计算1个考生的最终得分 3.状态对行为的约束 Preparing 状态下允许 2.1,2.2 操作 Ongoing 状态下允许2.3,2.4 操作 Finish 状态下不允许对该考生的任何数据改动操作

    考场状态类图

    考场状态类图

    考场状态类图说明

    state 接口:定义了每个具体类需要实现的接口方法is_match()用于判断对象的当前状态是否是当前状态类契合(对象状态的确定)。 InterceptState 接口的is_allowed() - 定义状态类的行为用于判断在当前状态下是否允许做当前操作(状态对行为的约束)。 InterceptStateBase : 所有状态类的父类
    1. granted_list : 用于保存当前对象允许执行的方法
    2. is_allowed() :搜索当前状态对象的granted_list,判断是否包含传入方法如果is_allowed返回false,那么对象代理将拒绝对该方法的调用。
    3. grant() :在初始化具体状态类时定义在当前状态下所有允许的方法
    4. deny() : 用于初始化具体状态类时定义不允许操作的方法(主要用于子状态允许操作的定制,在状态的层次会有详细描述)。 SceneState: 所有具体考场状态类的父类 具体的考场状态类: ScenePreparingState,SceneOngoingState,SceneFinishState

      考场状态类关键类代码片段

    [RegisterInContainer(LifeCycle.singleton)]
    [FriendlyName("考场准备")]
    public class ScenePreparingState : SceneState
    {
        public ScenePreparingState()
        {
            grant(x => x.add_examiner(null));
            grant(x => x.add_interviewee(0));
            grant(x => x.remove_examiner(null));
            grant(x => x.launch());
        }
        public override bool is_match(Scene target)
        {
            return target.Phase == Scene.Phases.Preparing;
        }
    }

    [RegisterInContainer(LifeCycle.singleton)]
    [FriendlyName("考场正在面试")]
    public class SceneOngoingState : SceneState
    {
        public SceneOngoingState()
        {
            grant(x=>x.start_interview(CandidateIdentifier.None));
            grant(x => x.reconsile(CandidateIdentifier.None));
        }

        public override bool is_match(Scene target)
        {
            return target.Phase == Scene.Phases.Ongoing;
        }

        public override bool is_allowed_scoring()
        {
            return true;
        }
    }

    [RegisterInContainer(LifeCycle.singleton)]
    [FriendlyName("考场面试结束")]
    public class SceneFinishState : SceneState
    {
        public SceneFinishState()
        {

        }
        public override bool is_match(Scene target)
        {
            return target.Phase == Scene.Phases.Finish;
        }
    }

为考场对象绑定动态代理

考场对象绑定动态代理时序图 考场状态类图

  1. 管理员导入考官
  2. ExamCommandImpl 获得考场对象scene
  3. 调用 scene的 enforce_stateful方法
  4. 在 enforce_stateful 方法内初始化状态拦截器StateProcessInterceptor
  5. 调用ProxyGenerator的CreateClassProxyWithTarget方法为scene对象绑定动态代理并注入拦截器对象

    考场对象调用add_examiner

    考场对象调用add_examiner方法时序图 考场对象调用add_examiner方法时序图

  6. 由于scene对象绑定了动态代理, scene的add_examiner方法被StateProcessInterceptor拦截
  7. 拦截器调用state_factory来判断当前scene是Preparing状态,获得ScenePreparingState对象
  8. 调用ScenePreparingState对象的isAllow方法获知在当前状态下允许调用 add_examiner
  9. 最终调用scene.add_examiner 方法

    优点

    当前状态的代理用C#的ProxyGenerator动态代理实现,开发人员只需要关注实现状态类

有层次的状态(一个对象的状态受其他对象的状态的影响)

包含子状态的业务场景

考场对象状态图

考场对象状态图

业务场景描述

如上图,当核分员选择考场点击开始考试,考场的状态从Preparing进入到 OnGoing。而一个考场有多位考生,一次会有一位考生面试。

业务场景中的状态

1> 考场的OnGoing(考场的面试进行中)状态包含2个子状态:“当前未有考生面试”,“当前考生正在面试” 2> “当前考生正在面试” 状态还包含2种子状态 “考生正在答题”,“考生正在待评分”

状态和对行为的约束

1> 考场的OnGoing所允许的行为 包括“开始一名考生的面试”,“对一名考生的面试进行核分” 2> “当前考生正在面试”状态下所允许的行为包括

包含子状态的业务逻辑的设计

考场状态对象的层次类图

考场状态对象的层次类图

对象说明和代码

如上图所示:由于采用了状态模式,把状态类化,就可以用继承来实现状态的层次。 以SceneInterviewingCandidateAnsweringState为例

  1. 该状态类继承自 SceneInterviewingState 也继承了基类对行为的约束(允许start_interview和reconsile)
  2. 但在该状态类而言,也略有不同之处,通过在初始化的时候deny start_interview方法实现对行为约束的定制
在考场的“一名考生正在面试”状态的子状态“考生正在答题”状态的实现代码
[RegisterInContainer(LifeCycle.singleton)]
    [FriendlyName("考生正在回答")]
    public class SceneInterviewingCandidateAnsweringState : SceneInterviewingState
    {
        public SceneInterviewingCandidateAnsweringState()
        {
            deny(x=>x.start_interview(CandidateIdentifier.None));//继承同时改变基类中对start_interview允许的定义
            grant(x=>x.restart_timer());
            grant(x=>x.pasue_timer());
            grant(x=>x.reset_timer());
            grant(x=>x.interview_complete());
        }

        public override bool is_match(Scene target)
        {
            return target.InterviewingCandidate!=null && target.InterviewingCandidate.Phases == CandidatePhases.Answering;
        }
    }
在考场的onGoing的实现代码
    public class SceneOngoingState : SceneState
    {
        public SceneOngoingState()
        {
            grant(x=>x.start_interview(CandidateIdentifier.None));
            grant(x => x.reconsile(CandidateIdentifier.None));
        }

        public override bool is_match(Scene target)
        {
            return target.Phase == Scene.Phases.Ongoing;
        }

        public override bool is_allowed_scoring()
        {
            return true;
        }
    }
在考场的onGoing的子状态“一名考生正在面试”状态的实现代码
     [RegisterInContainer(LifeCycle.singleton)]
     [FriendlyName("考场正在面试")]
    public class SceneInterviewingState : SceneOngoingState
    {
        public override bool is_match(Scene target)
        {
            return target.InterviewingCandidate != null;
        }
    }

有层次的状态设计的优点

由于通过状态模式把状态类化,可以利用类的继承和重载特性来实现子状态对父状态对行为的约束和重载,同时也使得对象状态的划分更加清晰和有层次。

( 本文版权属于© 2015 卓逸天成 | 转载请注明作者和出处:卓逸知识文库 http://kb.skight.com )