Single responsibility principle
클래스는 하나의 책임만 가지며 클래스는 그 책임을 완전히 캡슐화 해야 한다.
여러 책임을 갖고 있는 DataViewer 클래스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class DataViewer { public void display() { String data = loadHtml(); updateGui(data); } public String loadHtml() { HttpClient client = new HttpClient(); client.connect(url); return client.getResponse(); } private void updateGui(String data) { GuiData guiModel = parseDataToGuiData(data); tableUI.changeData(guiModel); } private GuiData parseDataToGuiData(String data) { } }
|
위 코드의 문제점
- 하나의 책임이 다른 책임까지 영향을 준다 (
data를 가져오는 방식이 HTTP방식에서 다른 방식으로 변경된다면, 관련된 모든 코드가 수정되어야 한다.)
data를 가져오는 새로운 방식이 추가됐다면, 사용하지 않더라도 불필요한 package를 포함되어야 한다.
개선방안
DataLoader, DataDisplayer 두가지 책임을 분리한다.
- 둘 간에 주고 받을 데이터를
String이 아닌 추상화된 타입으로 변경한다.
개선된 코드 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Data { ... } class DataLoader { public Data load() { ... } } class DataDisplayer { public void display(Data data) { ... } } class DataViewer { private DataLoader loader = new DataLoader(); private DataDisplayer displayer = new DataDisplayer(); public void display() { Data data = loader.load(); displayer.display(data); } public String loadData() { Data data = loader.load(); return dataToString(data); } }
|
남아있는 문제점
DataViewer가 DataLoader, DataDisplayer 두 클래스와 Composition을 관계를 형성하므로, 강한 coupling이 존재한다.
DataLoader, DataDisplayer 두 클래스가 변경되면, DataViewer 클래스가 영향을 받는다.
개선방안
DataLoader, DataDisplayer를 Aggregation으로 변경한다.
- 즉, 외부에서 의존성 주입을 한다. (객체간 life cycle 다름)
개선된 코드 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Data { ... } interface DataLoader { Data load(); } interface DataDisplayer { void display(Data data); } class DataViewer { private final DataLoader loader; private final DataDisplayer displayer; public DataViewer(DataLoader loader, DataDisplayer displayer) { this.loader = loader; this.displayer = displayer; } public void display() { Data data = loader.load(); displayer.display(data); } public String loadData() { Data data = loader.load(); return dataToString(data); } }
|
책임을 나누는 방법
- 많은 프로그래밍 경험을 바탕으로 감각적으로…(-_-;;)
- 매서드를 실행하는 주체(
Actor)를 확인해 본다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class GUIApplication { ... } class DataProcessor { ... } class DataViewer { public void display() { ... } public String loadData() { ... } }
|
위와 같은 상황이라면, GUIApplication 클래스는 DataViewer.display() 매서드를, DataProcessor클래스는 DataViewer.loadData() 매서드가 필요하므로, 두 매서드는 각각 다른 책임이므로 분리해야할 가능성이 높다.
참고자료