当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

《重构,改善现有代码的设计》第八章 Duplicate Observed Data

发表于: 2012-12-04   作者:bylijinnan   来源:转载   浏览:
摘要: 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.FocusE
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

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
Summary: 有一些领域数据置身于GUI控件中,而领域函数需要访问这些数据。将该数据复制到一个领域对
《重构,改善既有代码的设计》读书笔记 重构,绝对是写程序过程中最重要的事之一。在写程序之前我们
大型重构 1. Tease apart Inheritance 梳理并分解继承体系 某个继承体系同时承担两项责任 ,建立两个
重构,绝对是写程序过程中最重要的事之一。在写程序之前我们不可能事先了解所有的需求,设计肯定会
  如果一个人没有听说过《重构》这本书,那么他一定不敢说自己是程序员;如果一个人没有阅读过《
简化条件表达式 1.Decompose Conditional 分解条件表达式 你有一个复杂的条件语句。从if、then、els
重新组织数据: 1.Self Encapsulate Field 自封装字段 间接访问类的属性:你直接访问一个字段,但与
简化函数调用 1. Rename Method 函数改名 函数的名称未能揭示函数的用途。修改函数名称。 大力提倡
思维导图 介绍 承接上文的 PHP 杂谈《重构-改善既有代码的设计》之 重新组织你的函数继续重构方面的
思维导图 最近看了(川山甲)的博客,受益匪浅,所有记录下来 http://www.cnblogs.com/baochuan/ (
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号