2.1 类型1: Read-Only & Normal
2.1.1 动机
客户端GUI接受用户输入,经过数据有效性验证,然后将数据传输到服务端,服务端检查业务逻辑有效性,保存数据;但是在特定情况下(比如数据已经存在、且只能经历一次输入),依据客户端GUI所操作数据的状态,业务逻辑要求数据为只读,即客户端只具有显示数据的功能,并不能改变服务器上的数据。
一般地,编程实现时,会在GUI程序中加入判断数据是否应该为只读的逻辑判断语句。如果针对相同的数据集合(Model),有多个客户端GUI(View),就需要在每个程序中加入该判断。如此降低了程序的可维护性,决定数据是否为只读的这样一个业务逻辑将分散在程序中多处,不易维护,在业务逻辑发生改变时,易造成不一致。
我们可以将变化部分(在Normal和Read-Only状态下不同的部分)从GUI中抽取出来,分别用不同的类来表示,这样,当GUI的状态发生改变时,只需要改变其对状态对象的引用即可,状态相关操作委托给状态对象去完成。
2.1.2 适用性
本类型适用环境:相同数据集合,不同操作模式。即特定的GUI根据操作上下文环境,改变其响应模式,根据数据是否可编辑,分为两种状态Read-Only State、 Normal State。
2.1.3 结构(图2)
图2 相同数据集合,不同操作模式
2.1.4 参与者
ClientStateChangeable:客户端GUI提供给State对象的操作接口,使得State对象可以访问GUI的成员,以完成该状态相关操作;
getChangeableComponents():返回在状态转换为Read-Only时,不可编辑的控件Collection;
saveChangeToServer():在可编辑状态时,将客户端数据保存到服务端。
AClientGUI:完成图1中的Context功能,即其状态要进行改变的客户端GUI;维护ClientState的一个实例(state);
init():将this引用作为参数,调用state.setComponents(this) 以设置可变控件的初始状态;
okButtonActionPerformed(e:ActionEvent):用户完成操作后,本方法可作为 "OK"按钮控件的ActionListener方法,调用state.action(this) 以完成本操作。
ClientState:State接口,封装与客户端GUI某个特定状态相关的行为;
setComponents(gui:ClientStateChangeable):设置参数gui指定的客户端GUI的控件状态;
action(gui:ClientStateChangeable):完成数据保存功能。
ClientNormalState:可编辑状态子类,实现ClientState接口;
setComponents(gui:ClientStateChangeable):调用参数gui指定的客户端GUI的getChangeableComponents()获取控件Collection,然后遍历设置各控件状态为可编辑;
action(gui:ClientStateChangeable):调用参数gui指定的客户端GUI的saveChangeToServer()完成数据保存功能。
ClientReadOnlyState:只读状态子类,实现ClientState接口;
setComponents(gui:ClientStateChangeable):调用参数gui指定的客户端GUI的getChangeableComponents()获取控件Collection,然后遍历设置各控件状态为ReadOnly;
action(gui:ClientStateChangeable):空方法,本状态下无数据变化,无须保存。
2.1.5 代码示例
2
3 public interface ClientStateChangeable {
4
5 /**
6
7 * To get all changeable components in the GUI object.
8
9 * @return Collection contains Component objects.
10
11 */
12
13 Collection getChageableComponents();
14
15 /**
16
17 * To save data to server.
18
19 */
20
21 void saveChangeToServer();
22
23 }
24
25
AClientGUI类:
2
3 //…
4
5 private ClientState state = null;
6
7 public DesignStep1View(ClientState state){
8
9 //…
10
11 this.state = state;
12
13 this.state.setComponents(this);
14
15 }
16
17 private void okButton_actionPerformed(ActionEvent e){
18
19 state.action(this); //save data
20
21 }
22
23 public Collection getChageableComponents() {
24
25 Collection dataComponents = new ArrayList();
26
27 dataComponents.add(jComboBoxESEPattern);
28
29 //…
30
31 return dataComponents;
32
33 }
34
35 public void saveChangeToServer() {
36
37 //…
38
39 }
40
41 }
42
43
ClientState接口:
2 /**
3 * To set components' state in the GUI. * @param gui a GUI object which implements StateChangeable interface.
4 */
5 void setComponents(ClientStateChangeable gui);
6 /**
7 * when user click OK-Button in a GUI, the GUI will call this method.
8 * @param gui a GUI object which implements StateChangeable interface.
9 */
10 void action(ClientStateChangeable gui);
11 }
12
13
ClientNormalState类:
2
3 /**
4
5 * 正常状态下, 各个控件默认为可编辑的, 所以不用做任何更改
6
7 */
8
9 public void setComponents(ClientStateChangeable gui) {}
10
11 /**
12
13 * 正常状态下, 需要将用户所作修改保存到服务端
14
15 */
16
17 public void action(ClientStateChangeable gui) {
18
19 gui.saveChangeToServer();
20
21 }
22
23 }
24
25
ClientReadOnlyState类:
2
3 /**
4
5 * 设置GUI的数据控件为Read-Only
6
7 */
8
9 public void setComponents(ClientStateChangeable gui) {
10
11 Collection components = gui.getChageableComponents();
12
13 Iterator iter = components.iterator();
14
15 while(iter.hasNext()){
16
17 JComponent jc = (JComponent)iter.next();
18
19 jc.setEnabled(false);
20
21 String toolTip = jc.getToolTipText();
22
23 String addedTip = "只读状态";
24
25 if(toolTip == null)toolTip = addedTip;
26
27 else toolTip += ". " + addedTip;
28
29 jc.setToolTipText(toolTip);
30
31 }
32
33 }
34
35 /**
36
37 * GUI处于Read-Only状态, 无需将数据保存到server端
38
39 */
40
41 public void action(ClientStateChangeable gui) {}
42
43 }
44
45