- 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]+");
- }
- }