关闭

State状态设计模式(对象行为型)

标签: 设计模式
140人阅读 评论(0) 收藏 举报
分类:

意图:
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了他的类。

适用性
1) • 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
2) • 代码中包含大量与对象状态有关的条件语句:一个操作中含有庞大的多分支的条件(if else(或switch case)语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

结构
这里写图片描述

参与者
Context: 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
State: 定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState: 每一子类实现一个与Context的一个状态相关的行为。

协作

  • context将与状态相关的请求委托给当前的concretestate对象处理。
  • context可将自身作为一个参数传递给处理该请求的状态对象。这使得状态对象在必要时可访问context
  • context是客户使用的主要接口。客户可用状态对象来配置一个context。一旦一个context配置完毕,它的客户不再需要直接与状态对象打交道
  • context或concretestate子类都可决定哪个状态是另外哪一个的后继者,以及是在何种条件下进行状态转换

效果

状态模式的优点:
1 ) 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来: State模式将所有与一个特定的状态相关的行为都放入一个对象中。因为所有与状态相关的代码都存在于某一个State子类中, 所以通过定义新的子类可以很容易的增加新的状态和转换。另一个方法是使用数据值定义内部状态并且让 Context操作来显式地检查这些数据。但这样将会使整个Context的实现中遍布看起来很相似的条件if else语句或switch case语句。增加一个新的状态可能需要改变若干个操作, 这就使得维护变得复杂了。State模式避免了这个问题, 但可能会引入另一个问题, 因为该模式将不同状态的行为分布在多个State子类中。这就增加了子类的数目,相对于单个类的实现来说不够紧凑。但是如果有许多状态时这样的分布实际上更好一些, 否则需要使用巨大的条件语句。正如很长的过程一样,巨大的条件语句是不受欢迎的。它们形成一大整块并且使得代码不够清晰,这又使得它们难以修改和扩展。 State模式提供了一个更好的方法来组织与特定状态相关的代码。决定状态转移的逻辑不在单块的 i f或s w i t c h语句中, 而是分布在State子类之间。将每一个状态转换和动作封装到一个类中,就把着眼点从执行状态提高到整个对象的状态。这将使代码结构化并使其意图更加清晰。

2) 它使得状态转换显式化: 当一个对象仅以内部数据值来定义当前状态时 , 其状态仅表现为对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得转换变得更加明确。而且, State对象可保证Context不会发生内部状态不一致的情况,因为从 Context的角度看,状态转换是原子的—只需重新绑定一个变量(即Context的State对象变量),而无需为多个变量赋值

3) State对象可被共享 如果State对象没有实例变量—即它们表示的状态完全以它们的类型来编码—那么各Context对象可以共享一个State对象。当状态以这种方式被共享时, 它们必然是没有内部状态, 只有行为的轻量级对象。

状态模式的缺点:
1) 状态模式的使用必然会增加系统类和对象的个数。
2) 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

实现

public interface State {  

    // 封装四种动作  
    public void insertQuarter(); // 投币  
    public void ejectQuarter();  // 退币  
    public void turnCrank();     // 转动摇柄  
    public void dispense();      // 发糖果  
}  
  1. 实现具体的状态
// 没有投币的状态  
public class NoQuarterState implements State {  
    GumballMachine gumballMachine;  

    public NoQuarterState(GumballMachine gumballMachine) {  
        this.gumballMachine = gumballMachine;  
    }  

    public void insertQuarter() {  
        System.out.println("You inserted a quarter");  
        gumballMachine.setState(gumballMachine.getHasQuarterState());  
    }  

    public void ejectQuarter() {  
        System.out.println("You haven't inserted a quarter");  
    }  

    public void turnCrank() {  
        System.out.println("You turned, but there's no quarter");  
     }  

    public void dispense() {  
        System.out.println("You need to pay first");  
    }   

    public String toString() {  
        return "waiting for quarter";  
    }  
}  

[java] view plain copy
// 已经投币的状态  
public class HasQuarterState implements State {  
    GumballMachine gumballMachine;  

    public HasQuarterState(GumballMachine gumballMachine) {  
        this.gumballMachine = gumballMachine;  
    }  

    public void insertQuarter() {  
        System.out.println("You can't insert another quarter");  
    }  

    public void ejectQuarter() {  
        System.out.println("Quarter returned");  
        gumballMachine.setState(gumballMachine.getNoQuarterState());  
    }  

    public void turnCrank() {  
        System.out.println("You turned...");  
        gumballMachine.setState(gumballMachine.getSoldState());  
    }  

    public void dispense() {  
        System.out.println("No gumball dispensed");  
    }  

    public String toString() {  
        return "waiting for turn of crank";  
    }  
}  

// 正在售出的状态  
public class SoldState implements State {  

    GumballMachine gumballMachine;  

    public SoldState(GumballMachine gumballMachine) {  
        this.gumballMachine = gumballMachine;  
    }  

    public void insertQuarter() {  
        System.out.println("Please wait, we're already giving you a gumball");  
    }  

    public void ejectQuarter() {  
        System.out.println("Sorry, you already turned the crank");  
    }  

    public void turnCrank() {  
        System.out.println("Turning twice doesn't get you another gumball!");  
    }  

    public void dispense() {  
        gumballMachine.releaseBall();  
        if (gumballMachine.getCount() > 0) {  
            gumballMachine.setState(gumballMachine.getNoQuarterState());  
        } else {  
            System.out.println("Oops, out of gumballs!");  
            gumballMachine.setState(gumballMachine.getSoldOutState());  
        }  
    }  

    public String toString() {  
        return "dispensing a gumball";  
    }  
}  

[java] view plain copy
// 售完的状态  
public class SoldOutState implements State {  
    GumballMachine gumballMachine;  

    public SoldOutState(GumballMachine gumballMachine) {  
        this.gumballMachine = gumballMachine;  
    }  

    public void insertQuarter() {  
        System.out.println("You can't insert a quarter, the machine is sold out");  
    }  

    public void ejectQuarter() {  
        System.out.println("You can't eject, you haven't inserted a quarter yet");  
    }  

    public void turnCrank() {  
        System.out.println("You turned, but there are no gumballs");  
    }  

    public void dispense() {  
        System.out.println("No gumball dispensed");  
    }  

    public String toString() {  
        return "sold out";  
    }  
}  
  1. 实现Context
public class GumballMachine {  

    State soldOutState;  
    State noQuarterState;  
    State hasQuarterState;  
    State soldState;  

    State state = soldOutState;  
    int count = 0;  

    public GumballMachine(int numberGumballs) {  
        soldOutState = new SoldOutState(this);  
        noQuarterState = new NoQuarterState(this);  
        hasQuarterState = new HasQuarterState(this);  
        soldState = new SoldState(this);  

        this.count = numberGumballs;  
        if (numberGumballs > 0) {  
            state = noQuarterState;  
        }   
    }  

    public void insertQuarter() {  
        state.insertQuarter();  
    }  

    public void ejectQuarter() {  
        state.ejectQuarter();  
    }  

    public void turnCrank() {  
        state.turnCrank();  
        state.dispense();  
    }  

    void setState(State state) {  
        this.state = state;  
    }  

    void releaseBall() {  
        System.out.println("A gumball comes rolling out the slot...");  
        if (count != 0) {  
            count = count - 1;  
        }  
    }  

    int getCount() {  
        return count;  
    }  

    void refill(int count) {  
        this.count = count;  
        state = noQuarterState;  
    }  

    public State getState() {  
        return state;  
    }  

    public State getSoldOutState() {  
        return soldOutState;  
    }  

    public State getNoQuarterState() {  
        return noQuarterState;  
    }  

    public State getHasQuarterState() {  
        return hasQuarterState;  
    }  

    public State getSoldState() {  
        return soldState;  
    }  

    public String toString() {  
        StringBuffer result = new StringBuffer();  
        result.append("\nMighty Gumball, Inc.");  
        result.append("\nJava-enabled Standing Gumball Model #2004");  
        result.append("\nInventory: " + count + " gumball");  
        if (count != 1) {  
            result.append("s");  
        }  
        result.append("\n");  
        result.append("Machine is " + state + "\n");  
        return result.toString();  
    }  
}  
  1. 测试类
public class GumballMachineTestDrive {  

    public static void main(String[] args) {  
        GumballMachine gumballMachine = new GumballMachine(5);  

        System.out.println(gumballMachine);  

        gumballMachine.insertQuarter();  
        gumballMachine.turnCrank();  

        System.out.println(gumballMachine);  

        gumballMachine.insertQuarter();  
        gumballMachine.turnCrank();  
        gumballMachine.insertQuarter();  
        gumballMachine.turnCrank();  

        System.out.println(gumballMachine);  
    }  
}  

这样做的优点:
1. 将每个状态的行为局部化到自己的类中
2. 将容易产生问题的if语句删除,以方便日后的维护
3. 让每个状态”对修改关闭”,让糖果机”对拓展开放”,因为可以加入新的状态类
4. 创建一个新的代码基和类结构,这更能映射糖果的图,而且容易阅读和理解

本文实现部分参与于:http://blog.csdn.net/shuangde800/article/details/10132825

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9370次
    • 积分:605
    • 等级:
    • 排名:千里之外
    • 原创:51篇
    • 转载:15篇
    • 译文:0篇
    • 评论:9条
    文章分类