OCP를 만족시키면서 부분-전체 관계를 가지는 객체들 간의 관계를 정의할 때 쓸 수있다. 전체와 부분을 동일한 인터페이스로 관리할 수 있다.
composite pattern을 이해하기 위해서, 하나의 박스가 있다고 하자. 그리고 그 박스에는 컴퓨터의 부품들이 들어간다.
Box클래스를 만들고 Keyboard, Monitor, Speaker 객체들을 멤버로 가진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class Box {
private Keyboard keyboard;
private Monitor monitor;
private Speaker speaker;
public int getTotalPrice(){
return keyboard.getPrice() + monitor.getPrice() + speaker.getPrice();
}
public int getTotalPower(){
return keyboard.getPower() + monitor.getPower() + speaker.getPower();
}
//setter...
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
1
2
3
4
5
6
7
8
9
10
|
public class Speaker {
private int price;
private int power;
public Speaker(int price, int power) {
this.price = price;
this.power = power;
}
//getPrice, getPower...
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
1
2
3
4
5
6
7
8
9
10
11
|
public class Keyboard {
private int price;
private int power;
public Keyboard(int price, int power) {
this.price = price;
this.power = power;
}
//getPrice, getPower...
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
1
2
3
4
5
6
7
8
9
10
11
|
public class Monitor {
private int price;
private int power;
public Monitor(int price, int power) {
this.price = price;
this.power = power;
}
//getPrice, getPower...
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class Main {
public static void main(String[] args) {
Box box = new Box();
Keyboard keyboard = new Keyboard(100000,20);
Monitor monitor = new Monitor(200000,40);
Speaker speaker = new Speaker(70000,50);
box.setKeyboard(keyboard);
box.setMonitor(monitor);
box.setSpeaker(speaker);
int totalPrice = box.getTotalPrice();
int totalPower = box.getTotalPower();
System.out.println("total price : " + totalPrice);
System.out.println("total power : " + totalPower);
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
위의 코드는 Box 객체를 만들고, 그 객체에 setter를 이용해서 keyboard와 monitor, speaker를 주입한다.
그렇다면, 위의 코드에서 문제는 또 무엇일까? 이전과 마찬가지로 어떤 문제가 있는 지 생각하려면 바뀌는 것이 무엇인지 생각하면 된다.
mouse가 추가된다고 하자. 그러면 문제가 발생한다. Box클래스에 멤버변수로 mouse를 추가해줘야 한다. OCP를 만족하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class Box {
private Keyboard keyboard;
private Monitor monitor;
private Speaker speaker;
private Mouse mouse; //OCP를 만족하지 않는다!
//getTotalPrice와 getTotalPower에 각각 코드가 추가된다 -->OCP만족 X
public int getTotalPrice(){
return keyboard.getPrice() + monitor.getPrice() + speaker.getPrice() + mouse.getPrice();
}
public int getTotalPower(){
return keyboard.getPower() + monitor.getPower() + speaker.getPower() + mouse.getPower();
}
//setter...
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
OCP를 만족시키지 않기 때문에, 항상 했던 것처럼 일반화된 개념을 만들고 그 개념을 확장하는 자식 클래스를 만들면 된다.
1
2
3
4
5
|
public abstract class ComputeDevice {
public abstract int getPower();
public abstract int getPrice();
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
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
|
public class Box {
// private Keyboard keyboard;
// private Monitor monitor;
// private Speaker speaker;
private List<ComputeDevice> computeDeviceList = new ArrayList<ComputeDevice>();
public int getTotalPrice(){
return computeDeviceList.stream()
.sum();
}
public int getTotalPower(){
return computeDeviceList.stream()
.sum();
}
public void addComputerDevice(ComputeDevice computeDevice){
computeDeviceList.add(computeDevice);
}
public void rmComputerDevice(ComputeDevice computeDevice){
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
1
2
3
|
public class Speaker extends ComputeDevice
public class Keyboard extends ComputeDevice
public class Monitor extends ComputeDevice
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class Main {
public static void main(String[] args) {
Box box = new Box();
Keyboard keyboard = new Keyboard(100000,20);
Monitor monitor = new Monitor(200000,40);
Speaker speaker = new Speaker(70000,50);
box.addComputerDevice(keyboard);
box.addComputerDevice(monitor);
box.addComputerDevice(speaker);
int totalPrice = box.getTotalPrice();
int totalPower = box.getTotalPower();
System.out.println("total price : " + totalPrice);
System.out.println("total power : " + totalPower);
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
위와 같은 방식으로 하면, OCP를 만족시키고 여러 ComputerDevice를 추가할 수 있다.
하지만, 요구사항을 하나 추가해보도록 하자. 만약, Box안에 Box를 넣고 싶으면 어떻게 해야할까? 여기서 중요한 것은 부분과 전체를 구별하지 않고 같은 인터페이스로 해야한다. 즉, ComputerDevice를 넣는 addComputerDevice 메소드를 통해서 Box도 넣어야 한다. 마찬가지로, ComputerDevice를 제거하는 rmComputerDevice 메소드를 통해서 Box를 제거할 수 있어야한다.
의외로 이 문제는 아주 간단하게 풀린다. Box도 ComputerDevice의 자식클래스이면 된다.
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
34
|
public class Box extends ComputeDevice {
private List<ComputeDevice> computeDeviceList = new ArrayList<ComputeDevice>();
public int getTotalPrice(){
return computeDeviceList.stream()
.sum();
}
public int getTotalPower(){
return computeDeviceList.stream()
.sum();
}
public void addComputerDevice(ComputeDevice computeDevice){
computeDeviceList.add(computeDevice);
}
public void rmComputerDevice(ComputeDevice computeDevice){
}
@Override
public int getPower() {
return getTotalPower();
}
@Override
public int getPrice() {
return getTotalPrice();
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
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
|
public class Main {
public static void main(String[] args) {
Box box = new Box();
Keyboard keyboard = new Keyboard(100000,20);
Monitor monitor = new Monitor(200000,40);
Speaker speaker = new Speaker(70000,50);
box.addComputerDevice(keyboard);
box.addComputerDevice(monitor);
box.addComputerDevice(speaker);
System.out.println("total price : " + box.getTotalPrice()); //370000
System.out.println("total power : " + box.getTotalPower()); //110
Box smallBox = new Box();
Keyboard keyboard1 = new Keyboard(923400, 123);
smallBox.addComputerDevice(keyboard1);
box.addComputerDevice(smallBox);
System.out.println("total price : " + box.getTotalPrice()); //1293400
System.out.println("total power : " + box.getTotalPower()); //233
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
Box클래스가 ComputerDevice 클래스의 자식클래스가 된다면, Box클래스도 ComputerDevice와 같은 인터페이스를 가지게 된다. 그러면 Box와 ComputerDevice의 인터페이스가 구별되지 않는다.
컴포지트 패턴은 부분-전체 관계가 있는 클래스간의 관계를 나타날 때 사용하는 디자인패턴이다. 또한 전체는 부분과 같은 인터페이스를 사용할 수 있어서 전체가 부분이 될 수있다.
Composite pattern은 파일시스템에서 이루어지는 패턴이다. Box를 디렉터리라고 생각하고 ComputerDevice를 디렉터리가 아닌 파일이라고 생각하자(사실 디렉터리도 파일이다) 디렉터리는 파일을 가진다. 디렉터리는 디렉터리도 가질 수있다. 이 상황에 맞게 해결하려면 composite pattern이 가장 적절하다.
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
|
public class Main{
public static void main(String[] args){
//Home 디렉터리 생성
Directory homeDir = new Directory();
//파일 2개 생성
LinkFile linkFile1 = new LinkFile(....);
RegularFile regularFile1 = new RegularFile(....);
//Home디렉터리에 파일 2개를 위치시킨다.
homeDir.addFile(linkFile1);
homeDir.addFile(regularfile1);
//디렉터리 하나 생성
Directory dir1 = new Directory();
//1개의 소켓파일 생성
SocketFile socketFile1 = new SocketFile(....);
//dir1에 소켓파일을 위치시킨다.
dir1.addFile(socketFile1);
//homeDir에 dir1을 위치시킨다.
homeDir.addFile(dir1);
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
참고문헌
'Design pattern' 카테고리의 다른 글
[JAVA 디자인패턴] Decorator pattern(데커레이터 패턴) (3) | 2019.11.22 |
---|---|
[JAVA 디자인패턴] Observer pattern(옵저버 패턴) (0) | 2019.11.08 |
[JAVA 디자인패턴] Command pattern(커맨드 패턴) (0) | 2019.10.14 |
[JAVA 디자인패턴] SOLID 원칙 - 객체지향프로그래밍(OOP) 설계 (0) | 2019.10.09 |
[JAVA 디자인패턴] Strategy pattern(스트레티지 패턴, 전략패턴) (0) | 2019.10.02 |