本文介绍设计模式中的(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 discussion with 1-page examples in C++ and Java