이 실습에서는 Decorator와 Composite 패턴을 활용하여 동적 기능 확장과 트리 구조 객체 처리를 구현합니다.
실습 목표
- Decorator 패턴으로 동적 기능 확장 구현
- Composite 패턴으로 트리 구조 객체 처리
- 재귀적 구조와 투명성의 이해
- GUI 컴포넌트와 파일 시스템 모델링
실습 1: 음료 주문 시스템 (Decorator)
요구사항
다양한 토핑을 추가할 수 있는 음료 주문 시스템
코드 템플릿
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
| // TODO 1: Component 인터페이스 정의
public interface Beverage {
String getDescription();
double getCost();
int getCalories();
List<String> getIngredients();
}
// TODO 2: 기본 음료 구현 (ConcreteComponent)
public class Espresso implements Beverage {
// TODO: 에스프레소 기본 구현
}
public class DarkRoast implements Beverage {
// TODO: 다크로스트 기본 구현
}
public class HouseBlend implements Beverage {
// TODO: 하우스 블렌드 기본 구현
}
// TODO 3: Decorator 추상 클래스
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
// TODO: 기본 위임 구현
}
// TODO 4: 구체적인 Decorator들
public class Milk extends CondimentDecorator {
// TODO: 우유 추가 (+0.60원, +50칼로리)
}
public class Mocha extends CondimentDecorator {
// TODO: 모카 추가 (+0.80원, +80칼로리)
}
public class Whip extends CondimentDecorator {
// TODO: 휘핑크림 추가 (+0.70원, +60칼로리)
}
public class SoyMilk extends CondimentDecorator {
// TODO: 두유 추가 (+0.50원, +30칼로리)
}
// TODO 5: 음료 빌더 (Decorator 패턴 + Builder 패턴)
public class BeverageBuilder {
private Beverage beverage;
public static BeverageBuilder base(Beverage baseBeverage) {
// TODO: 기본 음료로 시작
return new BeverageBuilder();
}
public BeverageBuilder addMilk() {
// TODO: 우유 Decorator 추가
return this;
}
public BeverageBuilder addMocha() {
// TODO: 모카 Decorator 추가
return this;
}
public Beverage build() {
return beverage;
}
}
|
실습 2: 파일 시스템 (Composite)
요구사항
파일과 폴더를 동일하게 처리하는 파일 시스템
코드 템플릿
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| // TODO 1: Component 인터페이스
public interface FileSystemComponent {
String getName();
long getSize();
void display(int depth);
void add(FileSystemComponent component);
void remove(FileSystemComponent component);
List<FileSystemComponent> getChildren();
// TODO: 검색 기능
List<FileSystemComponent> search(String name);
List<FileSystemComponent> findByExtension(String extension);
}
// TODO 2: Leaf 구현 (File)
public class File implements FileSystemComponent {
private final String name;
private final long size;
private final String extension;
private final LocalDateTime lastModified;
// TODO: 파일 구현 (add, remove는 UnsupportedOperationException)
}
// TODO 3: Composite 구현 (Directory)
public class Directory implements FileSystemComponent {
private final String name;
private final List<FileSystemComponent> children;
private final LocalDateTime created;
// TODO: 디렉토리 구현 (재귀적 처리)
@Override
public long getSize() {
// TODO: 모든 하위 파일들의 크기 합계
return 0;
}
@Override
public void display(int depth) {
// TODO: 트리 구조로 출력
}
@Override
public List<FileSystemComponent> search(String name) {
// TODO: 재귀적 검색
return new ArrayList<>();
}
}
// TODO 4: 파일 시스템 유틸리티
public class FileSystemUtils {
// TODO: 전체 크기 계산
public static long getTotalSize(FileSystemComponent component) {
return 0;
}
// TODO: 깊이 우선 탐색
public static void walkFileSystem(FileSystemComponent root,
Consumer<FileSystemComponent> visitor) {
// TODO: 방문자 패턴과 결합
}
// TODO: 경로 찾기
public static String getPath(FileSystemComponent target,
FileSystemComponent root) {
return "";
}
}
|
실습 3: GUI 컴포넌트 시스템
코드 템플릿
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| // TODO 1: GUI Component (Composite)
public abstract class UIComponent {
protected String name;
protected int x, y, width, height;
protected boolean visible = true;
public abstract void render(Graphics graphics);
public abstract void add(UIComponent component);
public abstract void remove(UIComponent component);
// TODO: 이벤트 처리
public void handleClick(int x, int y) {
if (contains(x, y)) {
onClick();
}
}
protected abstract void onClick();
protected boolean contains(int x, int y) {
return x >= this.x && x <= this.x + width &&
y >= this.y && y <= this.y + height;
}
}
// TODO 2: 기본 컴포넌트들 (Leaf)
public class Button extends UIComponent {
private String text;
private Color backgroundColor;
// TODO: 버튼 렌더링 및 이벤트 처리
}
public class Label extends UIComponent {
private String text;
private Font font;
// TODO: 라벨 렌더링
}
// TODO 3: 컨테이너 컴포넌트들 (Composite)
public class Panel extends UIComponent {
private final List<UIComponent> children = new ArrayList<>();
private Color backgroundColor;
// TODO: 패널 렌더링 (자식들 포함)
@Override
public void handleClick(int x, int y) {
// TODO: 자식 컴포넌트들에게 이벤트 전파
}
}
// TODO 4: Decorator로 기능 확장
public abstract class UIComponentDecorator extends UIComponent {
protected UIComponent component;
// TODO: 기본 위임 구현
}
public class BorderDecorator extends UIComponentDecorator {
private final Color borderColor;
private final int borderWidth;
// TODO: 테두리 그리기
}
public class ScrollDecorator extends UIComponentDecorator {
private int scrollX, scrollY;
// TODO: 스크롤 기능 추가
}
|
실습 4: 로깅 시스템 (Decorator + Composite)
코드 템플릿
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
| // TODO 1: Logger 인터페이스
public interface Logger {
void log(LogLevel level, String message);
void log(LogLevel level, String message, Throwable throwable);
}
// TODO 2: 기본 Logger들 (ConcreteComponent)
public class ConsoleLogger implements Logger {
// TODO: 콘솔 출력
}
public class FileLogger implements Logger {
private final String filename;
// TODO: 파일 출력
}
// TODO 3: Logger Decorator들
public class TimestampDecorator implements Logger {
private final Logger logger;
// TODO: 타임스탬프 추가
}
public class FilterDecorator implements Logger {
private final Logger logger;
private final LogLevel minLevel;
// TODO: 로그 레벨 필터링
}
// TODO 4: Composite Logger
public class CompositeLogger implements Logger {
private final List<Logger> loggers;
// TODO: 여러 로거에 동시 출력
}
|
체크리스트
Decorator 패턴
Composite 패턴
패턴 조합
추가 도전
- Stream Decorator: Java Stream API 스타일 체이닝
- Cached Composite: 계산 결과 캐싱
- Async Decorator: 비동기 처리 장식자
- Reactive Composite: 변경 사항 자동 전파
실무 적용
Decorator 활용 사례
- HTTP 클라이언트 미들웨어
- 데이터베이스 커넥션 래핑
- 스트림 처리 파이프라인
- AOP (Aspect-Oriented Programming)
Composite 활용 사례
- GUI 컴포넌트 계층
- 조직도/메뉴 구조
- 수식 파서 (AST)
- 파일 시스템 모델링
핵심 포인트: Decorator는 수직적 기능 확장을, Composite는 수평적 구조 관리를 담당합니다. 두 패턴 모두 재귀적 구조를 통해 강력한 확장성과 유연성을 제공합니다.