重构第八章
6.Duplicate Observed Data(复制[被监视数据])
你有一些domain data(业务数据)置身于GUI控件中,而domain method(业务处理的方法)需要访问之。将该笔数据拷贝到一个domain object(业务对象)中。建立一个Observer模式,用以对domain object和GUI object内的复制数据进行同步控制。
Example:
public class IntervalWindow extends Frame...
java.awt.TextField _startField;
java.awt.TextField _endField;
java.awt.TextField _lengthField;
class SysFocus extends java.awt.event.FocusAdapter {
public void focusLost(java.awt.event.FocusEvent event) {
Object object = event.getSource();
if (object == _startField)
StartField_FocusLost(event);
else if (object == _endField)
EndField_FocusLost(event);
else if (object == _lengthField)
LengthField_FocusLost(event);
}
}
void StartField_FocusLost(java.awt.event.FocusEvent event) {
if (isNotInteger(_startField.getText()))
_startField.setText("0");
calculateLength();
}
void EndField_FocusLost(java.awt.event.FocusEvent event) {
if (isNotInteger(_endField.getText()))
_endField.setText("0");
calculateLength();
}
void LengthField_FocusLost(java.awt.event.FocusEvent event) {
if(isNotInteger(_lengthField.getText()))
_lengthField.setText("0");
calculateEnd();
}
void calculateLength() {
try {
int start = Integer.parseInt(_startField.getText());
int end = Integer.parseInt(_endField.getText());
int length = end - start;
_lengthField.setText(String.valueOf(length));
} catch (NumberFormatException e) {
throw new RuntimeException ("Unexpected Number Format Error!");
}
}
void calculateEnd() {
try {
int start = Integer.parseInt(_startField.getText());
int length = Integer.parseInt(_lengthield.getText());
int end = length + start;
_endField.setText(String.valueOf(end));
} catch (NumberFormatException e) {
throw new RuntimeException ("Unexpected Number Format Error!");
}
}
Analyse:
实例中,SysFocus()方法在鼠标焦点离开相应的文本框的时候,即相应的文本框失去焦点的时候开始工作,并传给对应的处理函数。
在对应的处理函数中,首先判断文本框的值是否为整数,不是的话,赋值为0,之后再进行相关的逻辑计算,计算end或者length的值。
此时,将处理业务逻辑的calculateLength()和calculateEnd()函数和界面处理函数分离开来。使用的方法是,讲这些数据复制到domain class中,并确保GUI class数据同步。这就是Duplicate Observed Data的任务。
End:
class Interval extends Observable { //建立domain class
private string _end = "0";
String getEnd() {
return _end;
}
void setEnd(String arg) {
_end = arg;
SetChanged();
notifyObservers(); //通知Observer数据已经被改变
}
void calculateLength() {
try {
length = end - start;
SetLength(String.valueOf(length));
} catch (NumberFormatException e) {
throw new RuntimeException ("Unexpected Number Format Error!");
}
}
void calculateEnd() {
try {
end = length + start;
setEnd(String.valueOf(end));
} catch (NumberFormatException e) {
throw new RuntimeException ("Unexpected Number Format Error!");
}
}
}
public class IntervalWindow extends Frame implements Observer
private Interval _subject; //建立联系
IntervalWindow() {
_subject = new Interval();
_subject.addObserver(this);
update(_subject,null);
}
//为end编辑框设置设值/取值函数即使用 Self Encapsulate Field(自封装值域)的方法
string getEnd() {
return _subject.getText();
}
void setEnd(String arg) {
_subject.setText(arg);
}
public void update (Observable observed, Object arg) {
_endField.setText(_subject.getEnd());
}
Conclusion:
使用Duplicate Observed Data(复制[被监视数据])方法可以是业务和GUI部分分离开来,之后独立对业务部分进行修改,或者对GUI部分修改,都会提供很大的便利。
注意
重构必须在有单元测试的情况下,保证之前的功能修改后不收影响。切记!!!
网友评论