2011년 5월 26일 목요일

Duplicate Observed Data



GUI 컨드롤에서만 사용 가능한 도메인 데이터가 있고 도메인 메소드에서 접근이 필요한 경우 그 데이터를 도메인 객체로 복사하고, Observer를 두어 두 데이터를 동기화 하라.

! 동기
  • 비즈니스 로직이 사용자 인터페이스와 섞여 있는 2-티어로 개발된 코드를 보게 되면 인터페이스와 동작을 분리 해야한다.
  • 이 작업은 대부분 메소드를 분해하고, 이동하는 것과 관련된다.
  • 데이터를 중복시키고 동기화하는 메커니즘을 제공하야 한다.

! 절차
  • 프리젠테이션 클래스를 도메인 클래스의 Observer로 만든다.
  • GUI 클래스 내의 도메인 데이터에 Self Encapsulate Field를 사용한다.
  • 이벤트 핸들러 안에 있는 set 메소드에 컴포넌트를 현재 값으로 업데이트하는 코드를 추가한다.
  • 도메인 클래스에 데이터와 접근자 메소드를 정의한다.
  • 접근자가 도메인 필드로 접근하도록 재지정 한다.
  • Observer의 update메소드가 도메인 필드의 데이터를 GUI컴포넌트로 복사하도록 수정한다.

예) 리팩토링 전 전체 소스
package refactoring.before;
import javax.swing.JFrame;
import java.awt.Dimension;
import javax.swing.JTextField;
import java.awt.Rectangle;
import javax.swing.JLabel;
import java.awt.event.FocusListener;
import java.awt.event.FocusEvent;
public class IntervalWindow extends JFrame  {
   private JTextField _startField  = new JTextField();
   private JTextField _endField    = new JTextField();
   private JTextField _lengthField = new JTextField();
   private JLabel Start  = new JLabel();
   private JLabel End    = new JLabel();
   private JLabel Length = new JLabel();
   public IntervalWindow() {
       try {
           jbInit();
       } catch(Exception e) {
           e.printStackTrace();
       }
   }
   private void jbInit() throws Exception {
       this.getContentPane().setLayout(null);
       this.setSize(new Dimension(400, 300));
       this.setTitle("Interval Window");
       _startField.setBounds(new Rectangle(150, 25, 125, 35));
       _startField.addFocusListener(new java.awt.event.FocusAdapter() {
               public void focusLost(FocusEvent e) {
                   _startField_focusLost(e);
               }
           });
       _endField.setBounds(new Rectangle(150, 80, 125, 35));
       _endField.addFocusListener(new java.awt.event.FocusAdapter() {
               public void focusLost(FocusEvent e) {
                   _endField_focusLost(e);
               }
           });
       _lengthField.setBounds(new Rectangle(150, 140, 125, 35));
       _lengthField.addFocusListener(new java.awt.event.FocusAdapter() {
               public void focusLost(FocusEvent e) {
                   _lengthField_focusLost(e);
               }
           });
       Start.setText("Start");
       Start.setBounds(new Rectangle(20, 25, 105, 35));
       End.setText("End");
       End.setBounds(new Rectangle(20, 80, 105, 35));
       Length.setText("Length");
       Length.setBounds(new Rectangle(20, 140, 105, 35));
       this.getContentPane().add(Length, null);
       this.getContentPane().add(End, null);
       this.getContentPane().add(Start, null);
       this.getContentPane().add(_lengthField, null);
       this.getContentPane().add(_endField, null);
       this.getContentPane().add(_startField, null);
       _startField.setText("10");
       _endField.setText("10");
       _lengthField.setText("0");
   }
   private void _startField_focusLost(FocusEvent e) {
       if(isNotInteger(_startField.getText()))
           _startField.setText("0");
       calculateLength();
   }
   private void _endField_focusLost(FocusEvent e) {
       if(isNotInteger(_endField.getText()))
           _endField.setText("0");
       calculateLength();
   }
   private void _lengthField_focusLost(FocusEvent e) {
       if(isNotInteger(_lengthField.getText()))
           _lengthField.setText("0");
       calculateEnd();
   }
   private boolean isNotInteger(String text){
       try{
           Integer.parseInt(text);
           return false;
       } catch(Exception e) {
           return true;
       }
   }
   private 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");
       }
   }
   private void calculateEnd() {
       try{
           int start  = Integer.parseInt(_startField.getText());
           int length = Integer.parseInt(_lengthField.getText());
           int end = length + start;
           _endField.setText(String.valueOf(end));
       } catch (NumberFormatException e) {
           throw new RuntimeException("Unexpected Number Format Error");
       }
   }
  
}


예) 리팩토링 적용 후
package refactoring.after;
import javax.swing.JFrame;
import java.awt.Dimension;
import javax.swing.JTextField;
import java.awt.Rectangle;
import javax.swing.JLabel;
import java.awt.event.FocusListener;
import java.awt.event.FocusEvent;
import java.util.*;
public class IntervalWindow extends JFrame implements Observer {
   private JTextField _startField  = new JTextField();
   private JTextField _endField    = new JTextField();
   private JTextField _lengthField = new JTextField();
   private JLabel Start  = new JLabel();
   private JLabel End    = new JLabel();
   private JLabel Length = new JLabel();
//--> 리팩토링 부분
   private Interval _subject;
//--> Observer 에 선언된 추상 메소드
   public void update(Observable observer, Object arg) {
       _endField.setText(_subject.getEnd());
       _startField.setText(_subject.getStart());
       _lengthField.setText(_subject.getLength());
   }
   public String getEnd() {
       return _subject.getEnd();
   }
   public void setEnd(String endText) {
       _subject.setEnd(endText);
   }
   public String getStart() {
       return _subject.getStart();
   }
   public void setStart(String startText) {
       _subject.setStart(startText);
   }
   public String getLength() {
       return _subject.getLength();
   }
   public void setLength(String lengthText) {
       _subject.setLength(lengthText);
   }
  
   public IntervalWindow() {
       try {
           jbInit();
       } catch(Exception e) {
           e.printStackTrace();
       }
   }
   private void jbInit() throws Exception {
       this.getContentPane().setLayout(null);
       this.setSize(new Dimension(400, 300));
       this.setTitle("Interval Window");
       _startField.setBounds(new Rectangle(150, 25, 125, 35));
       _startField.addFocusListener(new java.awt.event.FocusAdapter() {
               public void focusLost(FocusEvent e) {
                   _startField_focusLost(e);
               }
           });
       _endField.setBounds(new Rectangle(150, 80, 125, 35));
       _endField.addFocusListener(new java.awt.event.FocusAdapter() {
               public void focusLost(FocusEvent e) {
                   _endField_focusLost(e);
               }
           });
       _lengthField.setBounds(new Rectangle(150, 140, 125, 35));
       _lengthField.addFocusListener(new java.awt.event.FocusAdapter() {
               public void focusLost(FocusEvent e) {
                   _lengthField_focusLost(e);
               }
           });
       Start.setText("Start");
       Start.setBounds(new Rectangle(20, 25, 105, 35));
       End.setText("End");
       End.setBounds(new Rectangle(20, 80, 105, 35));
       Length.setText("Length");
       Length.setBounds(new Rectangle(20, 140, 105, 35));
       this.getContentPane().add(Length, null);
       this.getContentPane().add(End, null);
       this.getContentPane().add(Start, null);
       this.getContentPane().add(_lengthField, null);
       this.getContentPane().add(_endField, null);
       this.getContentPane().add(_startField, null);
       _subject = new Interval();
       _subject.addObserver(this);
       update(_subject,null);
       setStart("10");
       setEnd("9");
   }
   private void _startField_focusLost(FocusEvent e) {
       setStart(_startField.getText());
       if(isNotInteger(getStart()))
           setStart("0");
       _subject.calculateLength();
   }
   private void _endField_focusLost(FocusEvent e) {
       setEnd(_endField.getText());
       if(isNotInteger(getEnd()))
          setEnd("0");
       _subject.calculateLength();
   }
   private void _lengthField_focusLost(FocusEvent e) {
       setLength(_lengthField.getText());
       if(isNotInteger(getLength()))
           setLength("0");
       _subject.calculateEnd();
   }
   private boolean isNotInteger(String text){
       try{
           Integer.parseInt(text);
           return false;
       } catch(Exception e) {
           return true;
       }
   }   
}


package refactoring.after;
import java.util.Observable;
public class Interval extends Observable  {
   private String _start = "0";
   private String _end = "0";
   private String _length = "0";
   public Interval() {
   }
   public String getEnd() {
       return _end;
   }
   public void setEnd(String new_end) {
       _end = new_end;
       setChanged();
       notifyObservers();
   }
   public String getStart() {
       return _start;
   }
   public void setStart(String new_start) {
       _start = new_start;
       setChanged();
       notifyObservers();
   }
   public String getLength() {
       return _length;
   }
   public void setLength(String new_length) {
       _length = new_length;
       setChanged();
       notifyObservers();
   }
   public void calculateLength() {
       try{
           int start  = Integer.parseInt(getStart());
           int end    = Integer.parseInt(getEnd());
           int length = end - start;
           setLength(String.valueOf(length));
       } catch (NumberFormatException e) {
           throw new RuntimeException("Unexpected Number Format Error");
       }
   }
   public void calculateEnd() {
       try{
           int start  = Integer.parseInt(getStart());
           int length = Integer.parseInt(getLength());
           int end = length + start;
           setEnd(String.valueOf(end));
       } catch (NumberFormatException e) {
           throw new RuntimeException("Unexpected Number Format Error");
       }
   }   
}

댓글 없음:

댓글 쓰기

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...