Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2192524
  • 博文数量: 866
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10638
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/landuochong

文章分类

全部博文(866)

文章存档

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(70)

2011年(103)

2010年(360)

2009年(283)

2008年(22)

分类: C/C++

2010-11-26 17:18:37

State模式也叫状态模式,是由GoF提出的23种软件设计模式的一种。State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。


本文介绍设计模式中的(State)模式的概念,用法,以及实际应用中怎么样使用State模式进行开发。

State模式的概念与应用场景
State模式是行为模式之一。当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,这种情况可以考虑使用State模式来实现。
为了帮助理解,我们举例来说明。
一个画图程序,有一个控制面板,上面罗列了各种画图工具以及其它颜色选择,滴管等工具,当用户选择或改变了画图工具时,就可以使用各种不同的工具进行画图或其他操作了。
我们把这个过程用另外一种方法再描述一下:
- 用户选择画图工具就是一个画笔状态的改变。
- 每个工具能画的图形可能完全不一样,也就是说它们的行为各不一样。
- 改变了画图工具,在画布上画出的图形当然也不一样了,换句话说,画笔状态的改变导致行为的不一样。

怎么用程序实现这个过程呢?
我们先使用一般的方法(非State模式)来模拟选择画笔工具画图的过程:

//画笔工具选择事件处理方法
public void onSelectPen(int state) {
    //根据不同的选择创建不同的画笔工具,然后画图
    if (state == CIRCLE_PEN) {
        CirclePen cp = new CirclePen();    //创建圆形画笔
        cp.drawCircle(paramters);    //画圆形
    } else     if (state == SQUARE_PEN) {
        SquarePen sp = new SquarePen();    //创建方形画笔
        sp.drawSquare(paramters);    //画方形
    } else     if (state == LINE_PEN) {
        LinePen lp = new LinePen();
        lp.drawLine(paramters);
    }
    ...    //其他画笔

}
我们可以看到,需要为每一个画笔工具加一个判断条件,当画笔工具有增减或非常多时,代码不得不跟着作大量修改。

State模式对各种状态行为加以抽象,为每一个可能的状态创建一个状态类的子类,并通过一个Wrapper类管理状态子类对象的当前状态,对状态子类的调用加以封装。
用户可以通过改变Wrapper类对象所管理的状态来改变不同状态的行为。


State模式的结构


State模式的角色:
State
    对状态和状态行为的抽象。比如上面的例子,可以把每个画图工具看作状态的保持者。
ConcreteState
    各种状态的具体实现。比如画线工具,擦除工具等。
StateWrapper
    状态的外部封装类,或者说状态的容器类。它包含了对当前状态的引用。可以根据不同状态执行不同的行为。


State模式的应用范例

我们使用State模式来实现选择画笔工具进行画图的操作。

文件一览:
Client
    测试类。
AbstractTool
    相当于State角色。各种状态的抽象类。
LinePenTool
    相当于ConcreteState角色。画线工具类。
EraseTool
    相当于ConcreteState角色。图像擦除类。
ToolkitsPannel
    相当于StateWrapper角色。使用currentTool保持状态。可以通过selectTool方法改变其状态。

代码:
public class Client {
    /**
     * Test State Pattern
     *
     */

    public static void main(String[] args) {
        //创建工具面板
        ToolkitsPannel pannel = new ToolkitsPannel();
        
        //往工具面板上添加各种工具
        AbstractTool tool1 = new LinePenTool();
        pannel.addTool("LinePenTool", tool1);
        
        AbstractTool tool2 = new EraseTool();
        pannel.addTool("EraseTool", tool2);
        
        
        //选择LinePenTool工具(改变状态)
        pannel.selectTool("LinePenTool");
        pannel.drawOrExecute();
        
        //选择EraseTool工具(改变状态)
        pannel.selectTool("EraseTool");
        pannel.drawOrExecute();
    }
}

/**
* State & subclass
*
*/

abstract class AbstractTool {
    public abstract void drawOrExecute();
}

//State'subclass
class LinePenTool extends AbstractTool {
    public void drawOrExecute() {
        System.out.println("Draw line.");
    }
}

//State'subclass
class EraseTool extends AbstractTool {
    public void drawOrExecute() {
        System.out.println("Erase graph.");
    }
}

/**
* StateWrapper
*
*/

class ToolkitsPannel {
    //保持各种工具的列表
    Map toolsMap = new HashMap();
    
    AbstractTool currentTool;
    
    public void addTool(String toolName, AbstractTool tool) {
        toolsMap.put(toolName, tool);
    }
    
    //改变状态
    public void selectTool(String toolName) {
        currentTool = toolsMap.get(toolName);
    }
    
    //执行具体的行为
    public void drawOrExecute() {
        if (currentTool != null) {
            currentTool.drawOrExecute();
        } else {
            System.out.println("Please select a tool first.");
        }
    }
    
}



执行Client,输出结果:
C:\State>javac *.java
C:\State>java Client
Draw line.
Erase graph.
C:\State>
我们可以发现,通过改变ToolkitsPannel对象的状态(选择不同的画图工具),便改变了它的行为,其中并没有任何条件判断语句。


参考资料:

State pattern (Wikipedia)
State pattern discussion with 1-page examples in C++ and Java

 原文地址 http://www.lifevv.com/sysdesign/doc/20071129190226887.html
阅读(786) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册