* 여러 자료들을 참고했으나 제가 Composite Pattern에 대해 명확하게 이해한 것인지 확신하지 못하겠습니다.
개인 학습용 자료라 생각하고 정보가 필요하신 분들은 다른 곳을 참고하시길 바랍니다.
https://www.baeldung.com/java-composite-pattern
https://stackoverflow.com/questions/5334353/when-should-i-use-composite-design-pattern
Composite Pattern?
컴포짓 패턴이란 그룹 전체와 개별 객체를 동일하게 처리할 수 있는 패턴을 의미한다.
이는 즉 클라이언트 입장에서는 전체와 부분을 모두 동일한 컴포넌트로 인식할 수 있는 것이다.
위 그림을 보면 알겠지만 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public class BrushProgram2 {
String name = "BrushProgram2";
public void execute() {
System.out.println(this.name + " 실행");
}
}
public class CaptureProgram2 {
String name = "캡처 프로그램";
public void execute() {
System.out.println(this.name + " 실행");
}
}
public class LeagueOfLegends2 {
String name = "리그오브레전드";
public void execute() {
System.out.println(this.name + " 실행");
}
}
public class Starcraft2 {
String name = "스타크래프트";
public void execute() {
System.out.println(this.name + " 실행");
}
}
public class example2_App {
public static void main(String[] args) {
BrushProgram2 brushProgram2 = new BrushProgram2();
CaptureProgram2 captureProgram2 = new CaptureProgram2();
LeagueOfLegends2 leagueOfLegends2 = new LeagueOfLegends2();
Starcraft2 starcraft2 = new Starcraft2();
brushProgram2.execute();
captureProgram2.execute();
leagueOfLegends2.execute();
starcraft2.execute();
}
}
|
cs |
위와 같은 별 쓸모는 없는 클래스들이 있다고 가정해보자.
우리는 해당 클래스들에서 쉽게 공통 분모를 찾을 수 있다.
운영체제의 관점에서 봤을 때 해당 클래스들을 한 단계 추상화하면 "File"이라는 이름으로 추상화할 수 있을 것이다.
1
2
3
4
|
public interface File {
void execute();
}
|
cs |
볼품 없지만 아무튼 File이라는 인터페이스를 만들었다.
그런데 아직 약간 아쉽다, 좀 더 세분화된 추상화를 해보자.
캡처 프로그램과 브러쉬 프로그램은 유틸리티, 리그오브레전드와 스타크래프트는 게임으로 분류하면 어떨까?
그런데 우리가 만드는 건 Composite Design Pattern이라는 사실을 잊지 말자.
클라이언트단에서 File 하나로 모든 걸 사용 가능하게 할 것이기 때문에 File 밑으로 계층을 만들어줘야 한다.
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 Game implements File{
private String name;
public Game(String name) {
this.name = name;
}
@Override
public void execute() {
System.out.println(this.name + " 실행");
}
}
public class Utility implements File {
private String file;
public Utility(String file) {
this.file = file;
}
@Override
public void execute() {
System.out.println(this.file + " 실행");
}
}
|
cs |
만들고보니 이것도 interface로 만들던가 혹은 최소한 abstract로 만드는 게 적절하지 않았나 싶다.
(요즘 대세는 어떻게든 꾸역꾸역 interface로 맞춰서 만드는 쪽인 것 같다.)
예제를 수정하기 귀찮으니 interface나 abstract라고 생각해주자.
이제 이어서 우리가 필요한 클래스를 정의해주면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class BrushProgram extends Utility {
public BrushProgram(String file) {
super("BrushProgram");
}
}
public class CaptureProgram extends Utility {
public CaptureProgram(String file) {
super("CaptureProgram");
}
}
public class LeagueOfLegends extends Game{
public LeagueOfLegends() {
super("League of Legends");
}
}
public class Starcraft extends Game {
public Starcraft(String name) {
super("Starcraft");
}
}
|
cs |
여기까지 만들었으면 클라이언트단에서 어떻게 사용할 수 있는지 직접 확인해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class example2_App {
public static void main(String[] args) {
BrushProgram2 brushProgram2 = new BrushProgram2();
CaptureProgram2 captureProgram2 = new CaptureProgram2();
LeagueOfLegends2 leagueOfLegends2 = new LeagueOfLegends2();
Starcraft2 starcraft2 = new Starcraft2();
brushProgram2.execute();
captureProgram2.execute();
leagueOfLegends2.execute();
starcraft2.execute();
File lol = new LeagueOfLegends();
File star = new Starcraft();
File brush = new BrushProgram("좋은 브러쉬 프로그램");
File brush2 = new BrushProgram("구린 브러쉬 프로그램");
lol.execute();
star.execute();
brush.execute();
brush2.execute();
}
}
|
cs |
이전과 달리 File이라는 인터페이스 하나로 계층 내의 모든 객체들을 사용할 수 있게 되었다.
* 중요: Leaf는 Component가 아닌 다른 객체에 의존성을 가지면 안된다.
(예 : 만약 Composite Pattern 적용 이전에는 LeagueOfLegends의 필드에서 StarCraft 타입을 참조하고 있었더라도 Composite Pattern으로 변경 시 LeagueOfLegends는 File 타입을 참조해야함)
Composite Pattern의 장점은 다음과 같다.
1. 객체들이 모두 같은 타입으로 취급되어 복잡한 트리 구조를 편리하게 사용할 수 있다.
2. 다형성과 재귀 알고리즘을 활용할 수 있다.
Composite Pattern의 단점은 다음과 같다.
: 공통 인터페이스에 묶어서 추상화하기 때문에 과하게 추상화할 경우 오히려 설계가 패턴에 종속되어 전체 흐름을 망칠 우려가 있다.
따라서 디자인 패턴 적용 시에는 늘 해당 패턴을 적용하는 목적을 잘 생각해야 한다.
'CS ﹒ Algorithm > DesignPatterns' 카테고리의 다른 글
디자인 패턴 (7) Bridge Pattern : 브릿지 패턴 (0) | 2022.10.26 |
---|---|
디자인 패턴 (6) Adapter Pattern : 어댑터 패턴 (Spring HandlerAdapter 뜯어보기) (0) | 2022.10.23 |
디자인 패턴 (5) Prototype Pattern : 프로토타입 패턴 _ 애매한 녀석 (1) | 2022.09.30 |
디자인 패턴 (4) Builder Pattern : 빌더 패턴 _ 어노테이션부터 직접 구현까지 (0) | 2022.09.24 |
디자인 패턴 (3) Abstract-Factory Pattern : 추상 팩토리 패턴 & 팩토리 메서드와 비교하기 (0) | 2022.09.22 |