컴포지트 패턴
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 87개 중 75번째.
Composite Pattern은 객체를 트리 구조로 구성하여 부분-전체 계층을 나타낼 수 있게 하는 구조적 디자인 패턴입니다. 공통 인터페이스를 통해 클라이언트가 개별 객체와 객체의 구성을 동일하게 처리할 수 있도록 합니다.
파일 시스템을 생각해 보세요. 폴더에는 파일과 다른 폴더가 들어 있을 수 있고, 그 안에는 더 많은 파일과 폴더가 들어 있을 수 있습니다. 단일 파일을 다루든 전체 폴더 구조를 다루든, "크기 가져오기"와 같은 작업을 동일한 방식으로 수행하고 싶을 것입니다. 이 패턴은 Component 인터페이스, Leaf 객체(개별 요소), 그리고 자식 요소를 포함하는 컨테이너인 Composite 객체를 정의합니다.
interface FileComponent {
void display(String indent);
int getSize();
}
class File implements FileComponent {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public void display(String indent) {
System.out.println(indent + name + " (" + size + "KB)");
}
public int getSize() {
return size;
}
}
class Folder implements FileComponent {
private String name;
private List<FileComponent> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileComponent component) {
children.add(component);
}
public void display(String indent) {
System.out.println(indent + name + "/");
for (FileComponent child : children) {
child.display(indent + " ");
}
}
public int getSize() {
return children.stream().mapToInt(FileComponent::getSize).sum();
}
}composite는 작업을 children에 위임하여 재귀적 구조를 허용합니다. 클라이언트는 leaf와 함께 작업하는지 composite와 함께 작업하는지 알지 못한 채 트리와 상호 작용할 수 있습니다:
Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));
Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);
root.display("");
System.out.println("Total: " + root.getSize() + "KB");Composite Pattern은 조직도, UI component 또는 메뉴 시스템과 같은 계층 구조를 표현할 때 이상적이며, 그룹과 개별 항목을 동일하게 처리해야 하는 경우에 적합합니다.
챌린지
쉬움Composite Pattern을 사용하여 조직도 시스템을 만들어 봅시다! 부서가 employee와 하위 부서를 포함할 수 있는 구조를 만들고, 단일 employee를 보고 있든 전체 부서를 보고 있든 동일한 방식으로 총 급여를 계산하고 계층 구조를 표시할 수 있도록 합니다.
코드를 네 개의 파일로 구성합니다:
OrganizationComponent.java: employee와 부서가 모두 구현할 component 인터페이스를 Define합니다. 다음 두 메서드를 Declare해야 합니다: 적절한 들여쓰기로 component를 표시하는showDetails(String indent)와 총 급여를 정수로 반환하는getSalary().Employee.java: 개별 worker를 나타내는 leaf class를 Create합니다.Employee에는 name (String)과 salary (int)가 있으며, 둘 다 constructor를 통해 설정됩니다.showDetails가 Call되면[indent][name]: $[salary]를 출력해야 합니다.getSalary메서드는 employee의 salary를 단순히 반환합니다.Department.java: employee와 하위 부서를 모두 보유할 수 있는 composite class를 Create합니다.Department에는 name (String)이 있으며OrganizationComponentchildren의 목록을 유지합니다. 구성원을 추가하기 위한add(OrganizationComponent component)메서드를 가져야 합니다.showDetails가 Call되면[indent][name] Department를 출력한 다음, 들여쓰기를 늘려(공백 두 개 추가) 각 child에 대해showDetails를 Call합니다.getSalary메서드는 모든 child의 salary 합계를 반환합니다.Main.java: 조직을 Build합니다! 네 개의 입력을 받습니다. 두 employee의 name과 salary, 그리고 하위 부서의 name과 한 employee입니다.루트로 "Engineering" 부서를 Create합니다. 첫 번째 두 name/salary 쌍을 사용하여 employee 두 명을 추가합니다. 그런 다음 세 번째 입력을 사용하여 하위 부서를 Create하고, 네 번째 name/salary 쌍을 사용하여 employee 한 명을 추가한 뒤 이 하위 부서를 Engineering에 추가합니다.
Engineering 부서에서
showDetails("")를 Call한 다음,Total Salary: $[amount]형식으로 총 salary를 출력합니다.
입력은 다음 순서로 받습니다: employee1 name (String), employee1 salary (int), employee2 name (String), employee2 salary (int), 하위 부서 name (String), employee3 name (String), employee3 salary (int).
예를 들어 입력이 Alice, 75000, Bob, 65000, QA, Charlie, 55000라면 출력은 다음과 같습니다:
Engineering Department
Alice: $75000
Bob: $65000
QA Department
Charlie: $55000
Total Salary: $195000동일한 showDetails 및 getSalary 메서드가 단일 employee에서 Call되든, 중첩된 하위 부서를 포함하는 전체 부서에서 Call되든 원활하게 작동한다는 점에 주목하세요. composite 구조가 재귀를 자동으로 처리하므로 전체 계층 구조를 일관된 방식으로 다룰 수 있습니다!
직접 해보기
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 입력 읽기
String emp1Name = scanner.nextLine();
int emp1Salary = Integer.parseInt(scanner.nextLine());
String emp2Name = scanner.nextLine();
int emp2Salary = Integer.parseInt(scanner.nextLine());
String subDeptName = scanner.nextLine();
String emp3Name = scanner.nextLine();
int emp3Salary = Integer.parseInt(scanner.nextLine());
// TODO: Create the "Engineering" department as the root
// TODO: emp1과 emp2 데이터를 사용하여 Engineering에 직원 2명 생성 및 추가
// TODO: subDeptName을 사용하여 하위 부서 생성
// TODO: emp3 데이터를 사용하여 하위 부서에 직원 1명 생성 및 추가
// TODO: Engineering에 하위 부서 추가
// TODO: Call showDetails("") on the Engineering department
// TODO: 다음 형식으로 총 급여 출력: Total Salary: $[amount]
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조직접 연습해 보세요: 온라인 Java 컴파일러