상세 컨텐츠

본문 제목

관측 데이터 복제 리팩토링

자바강좌/리팩토링

by somiyuralove 2020. 2. 13. 21:47

본문

- 혼재하는 모델과 뷰를 분리, 단지 분리할 뿐이라면 서로 동기화되지 않으므로 관차자 패턴(Observer pattern)이나
이벤트 리스너를 사용해서 모델 내용이 변하면 그 사실을 뷰에 알리고 모델과 뷰를 동기화함.
- 뷰는 모델의 데이터를 복사한 형태로 가지고, 롼찰자 패턴이나 이벤트 리스너로 그 두 데이터를 동기화 한다는 의미를 가짐.

* 리팩토링 전 코드

package DuplicationObservedData.before;

import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class IntegerDisplay extends Frame implements ActionListener {
private final Label _octalLabel = new Label("0");
private final Label _decimalLabel = new Label("0");
private final Label _hexadecimalLabel = new Label("0");
private final Button _incrementButton = new Button("+");
private final Button _decrementButton = new Button("-");

private int _value = 0;

public IntegerDisplay() {
super("IntegerDisplay");

setLayout(new GridLayout(4,2));
add(new Label("Octal:"));
add(_octalLabel);
add(new Label("Decimal:"));
add(_decimalLabel);
add(new Label("Hexadecimal:"));
add(_hexadecimalLabel);
add(_incrementButton);
add(_decrementButton);

_incrementButton.addActionListener(this);
_decrementButton.addActionListener(this);

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}); 

pack();
setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == _incrementButton) {
setValue(_value +1);
} else if(e.getSource() == _decrementButton) {
setValue(_value - 1);
}
}

public int getValue() {
return _value;
}

public void setValue(int value) {
_value = value;
_octalLabel.setText(Integer.toString(_value, 8));
_decimalLabel.setText(Integer.toString(_value, 10));
_hexadecimalLabel.setText(Integer.toString(_value, 16));
}

}

* 리팩토링 후 코드

package DuplicationObservedData.after;

import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class IntegerDisplay extends Frame implements ActionListener, ValueListener {
private final Label _octalLabel = new Label("0");
private final Label _decimalLabel = new Label("0");
private final Label _hexadecimalLabel = new Label("0");
private final Button _incrementButton = new Button("+");
private final Button _decrementButton = new Button("-");

private Value _value = new Value(0);

public IntegerDisplay() {
super("IntegerDisplay");

setLayout(new GridLayout(4,2));
add(new Label("Octal:"));
add(_octalLabel);
add(new Label("Decimal:"));
add(_decimalLabel);
add(new Label("Hexadecimal:"));
add(_hexadecimalLabel);
add(_incrementButton);
add(_decrementButton);

_incrementButton.addActionListener(this);
_decrementButton.addActionListener(this);

_value.addValueListener(this);

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}); 

pack();
setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == _incrementButton) {
setValue(_value.getValue() +1);
} else if(e.getSource() == _decrementButton) {
setValue(_value.getValue() - 1);
}
}

public int getValue() {
return _value.getValue();
}

public void setValue(int value) {
_value.setValue(value);

}

@Override
public void valueChanged(ValueChangeEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == _value) {
_octalLabel.setText(Integer.toString(_value.getValue(), 8));
_decimalLabel.setText(Integer.toString(_value.getValue(), 10));
_hexadecimalLabel.setText(Integer.toString(_value.getValue(), 16));
}
}

}

package DuplicationObservedData.after;

import java.util.ArrayList;
import java.util.List;

public class Value {
private int _value = 0;
private final List _listeners = new ArrayList();

public Value(int value) {
_value = value;
}

public void setValue(int value) {
_value = value;
notifyToListeners();
}

public int getValue() {
return _value;
}

public void addValueListener(ValueListener listener) {
_listeners.add(listener);
}

public boolean removeValueListener(ValueListener listener) {
return _listeners.remove(listener);
}

private void notifyToListeners() {
for (ValueListener listener : _listeners) {
listener.valueChanged(new ValueChangeEvent(this));
}
}
}

package DuplicationObservedData.after;

public class ValueChangeEvent {
private final Value _source;
public ValueChangeEvent(Value source) {
_source = source;
}
public Value getSource() {
return _source;
}
}

package DuplicationObservedData.after;

public interface ValueListener {
public void valueChanged(ValueChangeEvent e);
}

package DuplicationObservedData.after;

public class Main {
public static void main(String[] args) {
new IntegerDisplay();
}
}

 

* 다른 이벤트 리스너 추가 코드

package DuplicationObservedData.graph;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;

public class Graph extends Canvas implements ValueListener {
public static final int RECTANGLE = 0;
public static final int CIRCLE = 1;
protected int _graphValue;

public static Graph createGraph(int type, int width, int height) {
Graph graph = null;
if (type == RECTANGLE) {
graph = new RectangleGraph();
} else if(type == CIRCLE) {
graph = new CircleGraph();
} else {
throw new RuntimeException("Unknown Graph type");
}
graph.setSize(new Dimension(width, height));
return graph;

}

@Override
public void valueChanged(ValueChangeEvent e) {
// TODO Auto-generated method stub
_graphValue = e.getSource().getValue();
repaint();
}

private static class RectangleGraph extends Graph {
public void paint(Graphics g) {
g.setColor(_graphValue > 0 ? Color.BLUE : Color.RED);
Rectangle bounds = getBounds();
int x, y, w, h;
if(_graphValue > 0) {
w = (int)(bounds.width / 2 * _graphValue / 100.0);
h = bounds.height / 2;
x = bounds.width / 2;
y = bounds.height / 4;
} else {
w = (int)(bounds.width / 2 * - _graphValue / 100.0);
h = bounds.height / 2;
x = bounds.width / 2 -w;
y = bounds.height / 4;
}
g.fillRect(x, y, w, h);
}
}

private static class CircleGraph extends Graph {
public void paint(Graphics g) {
g.setColor(_graphValue > 0 ? Color.BLUE : Color.RED);
Rectangle bounds = getBounds();
int startAngle = 90;
int endAngle = -(int)(_graphValue * 10.0);
g.fillArc(0, 0, bounds.width, bounds.height, startAngle, endAngle);
}
}

}

package DuplicationObservedData.graph;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class IntegerDisplay extends Frame implements ActionListener, ValueListener {
private final Label _octalLabel = new Label("0");
private final Label _decimalLabel = new Label("0");
private final Label _hexadecimalLabel = new Label("0");
private final Button _incrementButton = new Button("+");
private final Button _decrementButton = new Button("-");

private Value _value = new Value(0);

private final Graph _graphCircle = Graph.createGraph(Graph.CIRCLE, 100, 100);
private final Graph _graphRectangle = Graph.createGraph(Graph.RECTANGLE, 100, 50);

public IntegerDisplay() {
super("IntegerDisplay");

setLayout(new BorderLayout());

Panel panel = new Panel(new GridLayout(4,2));

panel.add(new Label("Octal:"));
panel.add(_octalLabel);
panel.add(new Label("Decimal:"));
panel.add(_decimalLabel);
panel.add(new Label("Hexadecimal:"));
panel.add(_hexadecimalLabel);
panel.add(_incrementButton);
panel.add(_decrementButton);

add(panel, BorderLayout.NORTH);
add(_graphCircle, BorderLayout.CENTER);
add(_graphRectangle, BorderLayout.SOUTH);

_incrementButton.addActionListener(this);
_decrementButton.addActionListener(this);

_value.addValueListener(this);

_value.addValueListener(_graphCircle);
_value.addValueListener(_graphRectangle);

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}); 

pack();
setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == _incrementButton) {
setValue(_value.getValue() +1);
} else if(e.getSource() == _decrementButton) {
setValue(_value.getValue() - 1);
}
}

public int getValue() {
return _value.getValue();
}

public void setValue(int value) {
_value.setValue(value);

}

@Override
public void valueChanged(ValueChangeEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == _value) {
_octalLabel.setText(Integer.toString(_value.getValue(), 8));
_decimalLabel.setText(Integer.toString(_value.getValue(), 10));
_hexadecimalLabel.setText(Integer.toString(_value.getValue(), 16));
}
}

}

package DuplicationObservedData.graph;

import java.util.ArrayList;
import java.util.List;

public class Value {
private int _value = 0;
private final List _listeners = new ArrayList();

public Value(int value) {
_value = value;
}

public void setValue(int value) {
_value = value;
notifyToListeners();
}

public int getValue() {
return _value;
}

public void addValueListener(ValueListener listener) {
_listeners.add(listener);
}

public boolean removeValueListener(ValueListener listener) {
return _listeners.remove(listener);
}

private void notifyToListeners() {
for (ValueListener listener : _listeners) {
listener.valueChanged(new ValueChangeEvent(this));
}
}
}

package DuplicationObservedData.graph;

public class ValueChangeEvent {
private final Value _source;
public ValueChangeEvent(Value source) {
_source = source;
}
public Value getSource() {
return _source;
}
}


package DuplicationObservedData.graph;

public interface ValueListener {
public void valueChanged(ValueChangeEvent e);
}


package DuplicationObservedData.graph;

public class Main {
public static void main(String[] args) {
new IntegerDisplay();
}
}

관련글 더보기

댓글 영역