import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Label;
import java.awt.TextField;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JFrame;
/**
* 《重构,改善现有代码的设计》第八章 Duplicate Observed Data
*
* 业务逻辑:
* 一个JFrame(类IntervalWindow)有三个TextField,分别是start,end和length
* 如果你修改Start或End,length就会自动成为两者计算所得的长度
* 如果你修改length,End就会随之改变(start不变)
*
* 主要是使用了Observer模式:
* start,end和length之间的运算,是与具体界面无关的,应该独立出来(成为一个Subject,观察者模式里面的“目标”)
*
* 关键在于解决以下两个问题:
* 1.什么时候计算?当界面上的TextField值有变动时,由WindowObserver调用Subject的set方法
* 2.计算后如何通知界面?Subject调用notifyObservers方法,这个方法会触发WindowObserver的update方法
*
*/
public class ObserveGUIWindow {
public static void main(String[] args) {
new WindowObserver().init();
}
}
class WindowObserver implements Observer {
private TextField startField;
private TextField endField;
private TextField lengthField;
private Subject subject;
public void init() {
JFrame f = new JFrame("This is a test");
f.setSize(200, 200);
Container content = f.getContentPane();
content.setBackground(Color.white);
content.setLayout(new FlowLayout());
startField = new TextField("0", 10);
endField = new TextField("0", 10);
lengthField = new TextField("0", 10);
SymFocus listener = new SymFocus();
startField.addFocusListener(listener);
endField.addFocusListener(listener);
lengthField.addFocusListener(listener);
Label startLabel = new Label("start:");
Label endLabel = new Label("end:");
Label lengthLabel = new Label("length:");
content.add(startLabel);
content.add(startField);
content.add(endLabel);
content.add(endField);
content.add(lengthLabel);
content.add(lengthField);
f.setLocationRelativeTo(null);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
subject = new Subject();
subject.addObserver(this);
}
//更新界面,最新的值(计算后)来自Subject
public void update(Observable o, Object arg) {
Subject subject = (Subject)o;
startField.setText(subject.getStart());
endField.setText(subject.getEnd());
lengthField.setText(subject.getLength());
}
class SymFocus extends FocusAdapter {
public void focusLost(FocusEvent event) {
Object object = event.getSource();
if (object == startField)
StartFieldFocusLost(event);
else if (object == endField)
EndFieldFocusLost(event);
else if (object == lengthField)
LengthFieldFocusLost(event);
}
}
void StartFieldFocusLost(FocusEvent event) {
//从界面取得输入的值
String start = startField.getText();
subject.setStart(isInteger(start) ? start : "0");
//交由Subject计算
subject.calculateLength();
}
void EndFieldFocusLost(FocusEvent event) {
String end = endField.getText();
subject.setEnd(isInteger(end) ? end : "0");
subject.calculateLength();
}
void LengthFieldFocusLost(FocusEvent event) {
String length = lengthField.getText();
subject.setLength(isInteger(length) ? length : "0");
subject.calculateEnd();
}
boolean isInteger(String str) {
return str != null && str.matches("[0-9]+");
}
}
class Subject extends Observable {
private String start = "0";
private String end = "0";
private String length = "0";
void calculateLength() {
try {
int start = Integer.parseInt(getStart());
int end = Integer.parseInt(getEnd());
int length = end - start;
this.setLength(String.valueOf(length));
} catch (NumberFormatException e) {
throw new RuntimeException("Unexpected Number Format Error");
}
}
void calculateEnd() {
try {
int start = Integer.parseInt(getStart());
int length = Integer.parseInt(getLength());
int end = start + length;
this.setEnd(String.valueOf(end));
} catch (NumberFormatException e) {
throw new RuntimeException("Unexpected Number Format Error");
}
}
public String getStart() {
return start;
}
public void setStart(String start) {
this.start = start;
//下面这两个方法在setter里面可以不调用,改到calculateEnd和calculateLength再调用更好
this.setChanged();
this.notifyObservers();
}
public String getEnd() {
return end;
}
public void setEnd(String end) {
this.end = end;
this.setChanged();
this.notifyObservers();
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
this.setChanged();
this.notifyObservers();
}
}
《重构,改善现有代码的设计》第八章 Duplicate Observed Data
最新推荐文章于 2020-01-01 19:11:14 发布