괴발나라

[GOF] 컴포지트 패턴으로 합체 로봇 만들기 🤖 본문

카테고리 없음

[GOF] 컴포지트 패턴으로 합체 로봇 만들기 🤖

괴발맨 2022. 2. 7. 21:02

컴포지트 패턴이란?

컴포지트 패턴은 GOF 디자인 패턴 중 한 패턴입니다.

컴포지트 패턴 클래스 다이어그램 - 위키 백과

컴포지트 패턴은 객체들의 관계가 트리 형태일때 유용합니다.

Composite 클래스의 객체가 여러개의 Leaf 클래스 객체를 갖게 됩니다.

둘은 모두 Component 인터페이스 또는 추상 클래스를 상속하여 같은 이름의 메서드를 구현하게 됩니다.

 

저도 잘 이해가 되지 않습니다.

곧장 합체 로봇을 만들어 보죠.


합체 로봇 만들기

저희는 합체 로봇 클래스를 만들 것입니다.

그리고 몸통, 팔, 다리를 클래스로 만들어 합체 진화시킬 예정입니다.

합체 로봇

먼저 합체 로봇 클래스를 만들어 봅시다!

class Robot {
    private Body body; // 몸통
    private Arms arms; // 팔
    private Legs legs; // 다리

    public void setBody(Body body) {
        this.body = body;
    }
    public void setArms(Arms arms) {
        this.arms = arms;
    }
    public void setLegs(Legs legs) {
        this.legs = legs;
    }

    void combine() {
        System.out.println(" === 로봇 합체 진화 시작 === ");
        this.body.combine(); // 몸통 합체!
        this.arms.combine(); // 팔 합체!
        this.legs.combine(); // 다리 합체!
        System.out.println(" === 전투 준비 완료 === ");
    }
}

그리고 몸통, 팔, 다리 등의 파트들을 클래스로 만듭니다.

class Body {
    void combine() {
        System.out.println("몸통 합체!");
    }
}

class Arms {
    void combine() {
        System.out.println("팔 합체!");
    }
}

class Legs {
    void combine() {
        System.out.println("다리 합체!");
    }
}

어린시절 추억이 떠올라 흥분이 됩니다.

하지만 너무 허전합니다.

제대로된 로봇이라면 날개도 있어야 합니다.

날개를 추가하려면 어떻게 해야 할까요?

 

Robot 클래스에 날개를 위한 클래스 변수를 추가해주고,

날개 클래스도 따로 만들어야 합니다.

합체 로봇 

날개 말고도 여러 파트들을 조합해

로봇을 더 강하고 멋있게 만들려면 어떻게 해야 할까요?

 

또 Robot 클래스를 수정하고, 클래스를 추가하고 

combine 메서드도 추가하고...

너무 번거롭습니다.

 

컴포지트 패턴으로 개선시켜 보겠습니다.

 


컴포지트 패턴으로 개선시키기 🎈

글 맨 위의 컴포지트 패턴 클래스 다이어그램을 다시 봅시다.

합체 로봇은 Composite, 나머지 파트들은 Leaf 에 해당됩니다.

그리고 이들은 모두 하나의 인터페이스를 상속할 것입니다.

 

먼저 Component 에 해당하는 RobotPart 인터페이스를 만들겠습니다.

interface RobotPart {
    void combine();
}

 

그리고 Robot 클래스가 이를 구현하도록 하겠습니다.

class Robot {
    private List<RobotPart> robotParts = new ArrayList<>();

    void addPart(RobotPart robotPart) { // 로봇 파트를 하나 추가합니다.
        if (!this.robotParts.contains(robotPart))
            this.robotParts.add(robotPart);
    }

    void removePart(RobotPart robotPart) { // 로봇 파트를 제거합니다.
        this.robotParts.remove(robotPart);
    }

    void combine() { // 합체진화 시킵니다
        System.out.println(" === 로봇 합체 진화 시작 === ");
        this.robotParts.forEach(RobotPart::combine); // 로봇이 갖고있는 모든 파트들을 합체시킵니다.
        System.out.println(" === 전투 준비 완료 === ");
    }
}

그런데 기존 Robot 클래스와 다른점은 

RobotPart의 리스트(List)를 클래스 변수로 갖습니다.

왜냐하면 Robot은 합체를 위해 여러개의 파트들이 필요하기 때문입니다.

 

이제 우리는 로봇에 원하는 파트를 자유롭게 붙혔다 뗐다 할 수 있게 됐습니다!

 

그러면 나머지 파트들도 완성시켜봅시다.

class Body implements RobotPart{
    public void combine() {
        System.out.println("몸통 합체!");
    }
}

class Arms implements RobotPart{
    public void combine() {
        System.out.println("팔 합체!");
    }
}

class Legs implements RobotPart{
    public void combine() {
        System.out.println("다리 합체!");
    }
}

 

한번 날개, 대포 등 원하는 파트들을 만들어보세요!

저는 날개 파트를 추가시켜보겠습니다.

class Wing implements RobotPart {
    public void combine() {
        System.out.println("날개 합체! ");
    }
}

 

이제 본격적으로 로봇에 원하는 파트들을 끼워

합체시켜보겠습니다.

public static void main(String[] args) {
    Robot robot = new Robot();

    robot.addPart(new Body());
    robot.addPart(new Arms());
    robot.addPart(new Legs());
    robot.addPart(new Wing());

    robot.combine();
}

한번 실행해 보시면 좋을 것 같습니다.

 

원하는 파트를 만들어 addPart 메서드로 추가하거나,

없애고 싶은 파트는 removePart 메서드로 없애고 갈아 치워버려도 됩니다 🤣 

 


결론

처음에는 로봇과 파트들을 만들어 합체시켜보았지만,

추가적인 파트를 합체시킬 경우에

너무 많은 변경점이 발생했습니다.

 

컴포지트 패턴으로 변경하며,

Composite에 해당하는 Robot 클래스를 변경시키지 않고도

원하는 파트들을 마음껏 추가할 수 있게 되었습니다.

 

다시 정리하자면,

컴포지트 패턴은 객체들의 관계를 트리 구조로 구성하여

부분(파트)-전체(로봇) 계층을 표현 하는 디자인 패턴입니다.

 

감사합니다.