zoukankan      html  css  js  c++  java
  • Duplicate Observed Data

      在翻看《重构-改善既有代码的设计》这本经典的书,书中就介绍了一个重构方法--Duplicate Observed Data 复制被监视数据的重构方法,使用这种方法能够使界面和对数据的操作隔离,去高度耦合。这样方便平台移植。

      网上也有这个方法的介绍,大多在抄书,抄写其中的文字,给出的代码也不是一个完整工程,我试着写出整个工程,整理出重构前和重构后的代码。

           重构前的完整例子是这样的,尽量保持与书中代码一致。

    package nelson.io;
    
    import java.awt.Frame;
    import java.awt.Label;
    import java.awt.TextField;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.FocusEvent;
    import java.awt.event.FocusListener;
    import java.awt.event.TextEvent;
    import java.awt.event.TextListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import javax.swing.Box;
    
    public class MainFrame{
    
        private Frame f = new Frame("测试");
        
        private TextField beginField = new TextField("");  
        private TextField endField = new TextField("");  
        private TextField lengthField = new TextField(""); 
        private Label beginLabel = new Label("Start:");
        private Label endLabel = new Label("End:");
        private Label lengthLabel = new Label("Length:");
        
        //定义水平摆放组件的Box对象  
        private Box horizontal1 = Box.createHorizontalBox();  
        private Box horizontal2 = Box.createHorizontalBox();
        private Box horizontal3 = Box.createHorizontalBox();
        private Box vertical1 = Box.createVerticalBox();
        
        public static void main(String [] args)
        {
            new MainFrame().init();
        }
        
        class SymFocus extends java.awt.event.FocusAdapter
        {
            public void focusLost(FocusEvent e) 
            {
                Object obj = e.getSource();
                if(obj == beginField)
                {
                    beginField_lostFocus(e);
                }
                else if(obj == endField)
                {
                    endField_lostFocus(e);
                }
                else if(obj == lengthField)
                {
                    lengthField_lostFocus(e);
                }
            }
        }
        
        private boolean isNotInteger(String strNum)
        {
            try
            {
                Integer.parseInt(strNum);
                return false;
            }
            catch (NumberFormatException e)
            {
                return true;
            }
        }
        
        public void beginField_lostFocus(FocusEvent e)
        {
            if(isNotInteger(beginField.getText()))
                beginField.setText("0");
            
            calculateLength();
        }
        
        public void endField_lostFocus(FocusEvent e)
        {
            if(isNotInteger(endField.getText()))
                endField.setText("0");
            
            calculateLength();
        }
        
        public void lengthField_lostFocus(FocusEvent e)
        {
            if(isNotInteger(lengthField.getText()))
                lengthField.setText("0");
            
            calculateEnd();
        }
        
        /*
         * 初始化界面
         */
        public void init()
        {
            beginField.addFocusListener(new SymFocus());
            endField.addFocusListener(new SymFocus());
            lengthField.addFocusListener(new SymFocus());
            horizontal1.add(beginLabel);
            horizontal1.add(beginField);
            horizontal2.add(endLabel);
            horizontal2.add(endField);
            horizontal3.add(lengthLabel);
            horizontal3.add(lengthField);
            vertical1.add(horizontal1);
            vertical1.add(horizontal2);
            vertical1.add(horizontal3);
            f.add(vertical1);
            f.pack();
            f.setSize(300, 120);
            f.setVisible(true);
            f.addWindowListener(new WindowAdapter(){
                
                public void windowClosing(WindowEvent e)
                {
                    System.exit(0);
                }
            });
        }
        
       /** 
        * 计算结束的值 
        */  
       private void calculateEnd() { 
           try{
               int begin=Integer.parseInt(this.beginField.getText());  
               int length=Integer.parseInt(this.lengthField.getText());  
               int end=length+begin;  
               this.endField.setText(String.valueOf(end));  
           }
           catch(java.lang.NumberFormatException e)
           {
               this.beginField.setText(String.valueOf(0));
               this.endField.setText(String.valueOf(0));
               this.lengthField.setText(String.valueOf(0));
           }
       }
     
       /*
        *计算长度的值  
        */  
       private void calculateLength() { 
           try{
               int begin=Integer.parseInt(this.beginField.getText());  
               int end=Integer.parseInt(this.endField.getText());  
               int length=end-begin;  
               this.lengthField.setText(String.valueOf(length));  
           }
           catch(java.lang.NumberFormatException e)
           {
               this.beginField.setText(String.valueOf(0));
               this.endField.setText(String.valueOf(0));
               this.lengthField.setText(String.valueOf(0));
           }
       }  
    }  

      程序运行结果如下,大致完善。

           

      下面再给出重构后的代码:

    package nelson.io;
    
    import java.awt.Frame;
    import java.awt.Label;
    import java.awt.TextField;
    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.Box;
    
    public class MainFrame implements Observer{
    
        private Frame f;
        
        //控件
        private TextField beginField;
        private TextField endField;  
        private TextField lengthField; 
        private Label beginLabel;
        private Label endLabel;
        private Label lengthLabel;
        
        //定义水平摆放组件的Box对象  
        private Box horizontal1 = Box.createHorizontalBox();  
        private Box horizontal2 = Box.createHorizontalBox();
        private Box horizontal3 = Box.createHorizontalBox();
        private Box vertical1 = Box.createVerticalBox();
        
        //内部模型类对象
        private Interval _subject;
        
        public static void main(String [] args)
        {
            new MainFrame().init();
        }
        
        //构造器
        public MainFrame()
        {
            f = new Frame("测试");
            beginLabel = new Label("Start:");
            endLabel = new Label("End:");
            beginField = new TextField("");
            endField = new TextField("");
            lengthField = new TextField("");
            lengthLabel = new Label("Length:");
            
            _subject = new Interval();
            _subject.addObserver(this);
            update(_subject,null);
        }
        
        public void update(Observable o, Object arg)
        {
            endField.setText(_subject.getEnd());
            beginField.setText(_subject.getBegin());
            lengthField.setText(_subject.getLength());
        }
        
        public String getEnd()
        {
            return _subject.getEnd();
        }
        
        public void setEnd(String end)
        {
            _subject.setEnd(end);
        }
        
        public String getBegin()
        {
            return _subject.getBegin();
        }
        
        public void setBegin(String begin)
        {
            _subject.setBegin(begin);
        }
        
        public String getLength()
        {
            return _subject.getLength();
        }
        
        public void setLength(String length)
        {
            _subject.setLength(length);
        }
    
        class SymFocus extends java.awt.event.FocusAdapter
        {
            public void focusLost(FocusEvent e) 
            {
                Object obj = e.getSource();
                if(obj == beginField)
                {
                    beginField_lostFocus(e);
                }
                else if(obj == endField)
                {
                    endField_lostFocus(e);
                }
                else if(obj == lengthField)
                {
                    lengthField_lostFocus(e);
                }
            }
        }
        
        private boolean isNotInteger(String strNum)
        {
            try
            {
                Integer.parseInt(strNum);
                return false;
            }
            catch (NumberFormatException e)
            {
                return true;
            }
        }
        
        public void beginField_lostFocus(FocusEvent e)
        {
            if(isNotInteger(beginField.getText()))
                setBegin("0");
            else
                setBegin(beginField.getText());
            _subject.calculateLength();
        }
        
        public void endField_lostFocus(FocusEvent e)
        {
            if(isNotInteger(endField.getText()))
                setEnd("0");
            else
                setEnd(endField.getText());
            
            _subject.calculateLength();
        }
        
        public void lengthField_lostFocus(FocusEvent e)
        {
            if(isNotInteger(lengthField.getText()))
                setLength("0");
            else
                setLength(lengthField.getText());
            _subject.calculateEnd();
        }
        
        /*
         * 初始化界面
         */
        public void init()
        {
            beginField.addFocusListener(new SymFocus());
            endField.addFocusListener(new SymFocus());
            lengthField.addFocusListener(new SymFocus());
            horizontal1.add(beginLabel);
            horizontal1.add(beginField);
            horizontal2.add(endLabel);
            horizontal2.add(endField);
            horizontal3.add(lengthLabel);
            horizontal3.add(lengthField);
            vertical1.add(horizontal1);
            vertical1.add(horizontal2);
            vertical1.add(horizontal3);
            f.add(vertical1);
            f.pack();
            f.setSize(300, 120);
            f.setVisible(true);
            f.addWindowListener(new WindowAdapter(){
                
                public void windowClosing(WindowEvent e)
                {
                    System.exit(0);
                }
            });
        }
    }
    
    class Interval extends Observable {
        private String _end = "0";
        private String _begin = "0";
        private String _length = "0";
    
        public String getEnd() {
            return _end;
        }
    
        public void setEnd(String end) {
            _end = end;
            setChanged();
            notifyObservers();
        }
    
        public String getBegin() {
            return _begin;
        }
    
        public void setBegin(String begin) {
            _begin = begin;
            setChanged();
            notifyObservers();
        }
    
        public String getLength() {
            return _length;
        }
    
        public void setLength(String length) {
            _length = length;
            setChanged();
            notifyObservers();
        }
    
        public void calculateEnd() {
            try {
                int begin = Integer.parseInt(getBegin());
                int length = Integer.parseInt(getLength());
                int end = length + begin;
                setEnd(String.valueOf(end));
            } catch (java.lang.NumberFormatException e) {
    
            }
        }
    
        /*
         * 计算长度的值
         */
        public void calculateLength() {
            try {
                int begin = Integer.parseInt(getBegin());
                int end = Integer.parseInt(getEnd());
                int length = end - begin;
                setLength(String.valueOf(length));
            } catch (java.lang.NumberFormatException e) {
    
            }
        }
    }

      总结一下重构过程:

      1、界面中的文本框元素与中间类中的文本数据一一对应,也就是Duplicate Observerd Data。

      2、界面类中的数据赋值与取值函数全部委托给中间类,当然对数据计算肯定也是在中间类中完成的,界面类根本不需要知道中间类中计算过程的存在,界面类只复制界面的显示。

      3、中间类中数据的更新需要通知界面类,这里使用了Java的Observer模式。相当于界面在中间类中注册了一个回调函数。

           上述代码依然可以再次重构,比如中间类Interval名称就应该改为数据模型类MainFramModel(针对MainFrame界面的数据模型model)。另外,文本框内容变动时的响应函数里,在响应函数里做了对输入规范(要求是数据)的判断,其实依然可以交给数据模型类来处理,相对于给数据模型类的元素赋值函数处理时的输入数据校验,这样界面类更简洁更纯粹。另外,文本框内容的变动可能由网络数据更新(或者其他渠道更新),这样数据模型类就应该申明成public型,作为一个单独的文件,与界面类的隔离更彻底。

      再次整理后的代码如下:

      界面类:

    package nelson.io;
    
    import java.awt.Frame;
    import java.awt.Label;
    import java.awt.TextField;
    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.Box;
    
    public class MainFrame implements Observer{
    
        private Frame f;
        
        //控件
        private TextField beginField;
        private TextField endField;  
        private TextField lengthField; 
        private Label beginLabel;
        private Label endLabel;
        private Label lengthLabel;
        
        //定义水平摆放组件的Box对象  
        private Box horizontal1 = Box.createHorizontalBox();  
        private Box horizontal2 = Box.createHorizontalBox();
        private Box horizontal3 = Box.createHorizontalBox();
        private Box vertical1 = Box.createVerticalBox();
        
        private MainFrameModel _datamodel;   //对应界面的数据模型
        
        //构造器
        public MainFrame()
        {
            f = new Frame("测试");
            beginLabel = new Label("Start:");
            endLabel = new Label("End:");
            beginField = new TextField("");
            endField = new TextField("");
            lengthField = new TextField("");
            lengthLabel = new Label("Length:");
            
            _datamodel = new MainFrameModel();
            _datamodel.addObserver(this);
            update(_datamodel,null);
        }
        
        public void update(Observable o, Object arg)
        {
            endField.setText(_datamodel.getEnd());
            beginField.setText(_datamodel.getBegin());
            lengthField.setText(_datamodel.getLength());
        }
        
        public static void main(String [] args)
        {
            new MainFrame().init();
        }
        
        public String getEnd()
        {
            return _datamodel.getEnd();
        }
        
        public void setEnd(String end)
        {
            _datamodel.setEnd(end);
        }
        
        public String getBegin()
        {
            return _datamodel.getBegin();
        }
        
        public void setBegin(String begin)
        {
            _datamodel.setBegin(begin);
        }
        
        public String getLength()
        {
            return _datamodel.getLength();
        }
        
        public void setLength(String length)
        {
            _datamodel.setLength(length);
        }
        
        private void calculateLength()
        {
            _datamodel.calculateLength();
        }
        
        private void calculateEnd()
        {
            _datamodel.calculateEnd();
        }
    
        class SymFocus extends java.awt.event.FocusAdapter
        {
            public void focusLost(FocusEvent e) 
            {
                Object obj = e.getSource();
                if(obj == beginField)
                {
                    setBegin(beginField.getText());
                    calculateLength();
                }
                else if(obj == endField)
                {
                    setEnd(endField.getText());
                    calculateLength();
                }
                else if(obj == lengthField)
                {
                    setLength(lengthField.getText());
                    calculateEnd();
                }
            }
        }
    
        /*
         * 初始化界面
         */
        public void init()
        {
            beginField.addFocusListener(new SymFocus());
            endField.addFocusListener(new SymFocus());
            lengthField.addFocusListener(new SymFocus());
            horizontal1.add(beginLabel);
            horizontal1.add(beginField);
            horizontal2.add(endLabel);
            horizontal2.add(endField);
            horizontal3.add(lengthLabel);
            horizontal3.add(lengthField);
            vertical1.add(horizontal1);
            vertical1.add(horizontal2);
            vertical1.add(horizontal3);
            f.add(vertical1);
            f.pack();
            f.setSize(300, 120);
            f.setVisible(true);
            f.addWindowListener(new WindowAdapter(){
                
                public void windowClosing(WindowEvent e)
                {
                    System.exit(0);  
                }
            });
        }
    }

      数据模型类:

    package nelson.io;
    
    import java.util.Observable;
    
    public class MainFrameModel extends Observable{
    
        private String _end = "0";
        private String _begin = "0";
        private String _length = "0";
        
        public MainFrameModel()
        {
            
        }
        
        public String getEnd() {
            return _end;
        }
    
        public void setEnd(String end) {
            int input=0;
            try
            {
                input = Integer.parseInt(end);
            }
            catch(NumberFormatException e)
            {
                input = 0;
            }
            _end = input+"";
            setChanged();
            notifyObservers();
        }
    
        public String getBegin() {
            return _begin;
        }
    
        public void setBegin(String begin) {
            int input=0;
            try
            {
                input = Integer.parseInt(begin);
            }
            catch(NumberFormatException e)
            {
                input = 0;
            }
            _begin = input+"";
            setChanged();
            notifyObservers();
        }
    
        public String getLength() {
            return _length;
        }
    
        public void setLength(String length) {
            int input=0;
            try
            {
                input = Integer.parseInt(length);
            }
            catch(NumberFormatException e)
            {
                input = 0;
            }
            _length = input+"";
            setChanged();
            notifyObservers();
        }
        
        public void calculateEnd() {
            int begin = Integer.parseInt(getBegin());
            int length = Integer.parseInt(getLength());
            int end = length + begin;
            setEnd(String.valueOf(end));
        }
    
        public void calculateLength() {
            int begin = Integer.parseInt(getBegin());
            int end = Integer.parseInt(getEnd());
            int length = end - begin;
            setLength(String.valueOf(length));
        }
    }

      整理完毕。

      

  • 相关阅读:
    左偏树
    论在Windows下远程连接Ubuntu
    ZOJ 3711 Give Me Your Hand
    SGU 495. Kids and Prizes
    POJ 2151 Check the difficulty of problems
    CodeForces 148D. Bag of mice
    HDU 3631 Shortest Path
    HDU 1869 六度分离
    HDU 2544 最短路
    HDU 3584 Cube
  • 原文地址:https://www.cnblogs.com/kanite/p/7156329.html
Copyright © 2011-2022 走看看