디자인 패턴 - 컴포지트 패턴 (Composite Pattern)

  • Composite 란 영어사전상 "복합체" 라는 뜻.
  • 소프트웨어적으로는 하나 이상의 유사한 객체를 구성으로 설계된 객체로서, 모두 유사한 기능을 나타내는 것을 뜻한다.
  • 즉, 객체 그룹을 조작하는 것처럼 단일 객체를 조작할 수 있음.

  • 컴포지트 패턴은 클라이언트가 복합 객체나 단일 객체를 동일하게 취급하는 것을 목적으로 함.
  • 이 때, 컴포지트의 의도는 "트리 구조"로 작성하여, 전체-부분(whole-part) 관계를 표현하는 것이다.
  • 즉, 전체-부분 관계를 효율적으로 정의할 때 컴포지트 패턴은 유용하다.

  • Composite 패턴에는 3가지로 구조가 나뉘어져있다.
    1. Component
      • 구체적인 부분
      • Leaf 클래스와 Composite 클래스의 공통 인터페이스임
    2. Leaf
      • 구체적인 부분 클래스
      • Composite 객체의 부품
    3. Composite
      • 전체 클래스.
      • 여러개의 Component를 갖도록 정의한다.
      • 그래서 여러개의 Leaf, 여러개의 Composite를 부분으로 가질수도 있다.

예시

  • 강아지와 고양이는 동물이다.
  • 강아지그룹, 고양이그룹에 각각 2마리, 3마리 넣는다.
  • 두 그룹을 동물원에 넣는다.
  • 동물원 내의 동물들을 모두 speak 하게 만들면?

Component: IAnimal.java

// Component 역할
interface IAnimal {
    public void speak();
}

Leaf: Cat.java

public class Cat implements IAnimal{
    @Override
    public void speak() {
        System.out.println("야옹");
    }
}

Leaf: Dog.java

public class Dog implements IAnimal{
    @Override
    public void speak() {
        System.out.println("멍멍");
    }
}

Composite: AnimalGroup.java

// Composite 역할
public class AnimalGroup implements IAnimal {

    private List<IAnimal> animalGroup = new ArrayList<IAnimal>();

    public void speak() {
        for (IAnimal animal : animalGroup) {
            animal.speak();
        }
    }

    public void add(IAnimal animal) {
        animalGroup.add(animal);
    }

    public void remove(IAnimal animal) {
        animalGroup.remove(animal);
    }
}

Client: Main.java

public class Main {
    public static void main(String[] args) {

        // 강아지그룹, 고양이그룹 생성
        AnimalGroup dog_group = new AnimalGroup();
        AnimalGroup cat_group = new AnimalGroup();

        // 강아지 2마리, 고양이 3마리 만들어서 각 그룹에 넣기
        Dog dog1 = new Dog();
        Dog dog2 = new Dog();

        Cat cat1 = new Cat();
        Cat cat2 = new Cat();
        Cat cat3 = new Cat();

        dog_group.add(dog1);
        dog_group.add(dog2);

        cat_group.add(cat1);
        cat_group.add(cat2);
        cat_group.add(cat3);

        // 강아지그룹과 고양이그룹을 동물원이라는 그룹안에 넣겠음
        AnimalGroup zoo = new AnimalGroup();
        zoo.add(dog_group);
        zoo.add(cat_group);

        // 동물원의 모든 동물들을 speak 해보겠음
        zoo.speak();
    }
}

결과는 다음과 같이 나온다.

멍멍
멍멍
야옹
야옹
야옹

'TIL' 카테고리의 다른 글

SVN vs Git  (1) 2022.12.11
JPA fetchType (EAGER, LAZY)  (0) 2022.12.06
디자인패턴 - 프록시 패턴 (Proxy Pattern)  (0) 2022.11.08
프로그래머스 SQL 고득점 Kit 도장깨기  (0) 2022.10.29
URI, URL, URN 차이  (0) 2022.10.25

디자인 패턴 - 프록시 패턴 (Proxy Pattern)

  • Proxy는 우리말로 대리자, 대변인이라는 뜻이다.
  • Proxy는 흐름제어만 할 뿐, 결과값을 조작하거나, 변경시키면 안된다.

  • Proxy는 실제 서비스와 같은 이름의 메서드를 구현한다. 이 때 인터페이스를 사용한다.
  • Proxy는 실제 서비스에 대한 참조 변수를 갖는다.
  • Proxy는 실제 서비스의 같은 이름을 가진 메서드를 호출하고, 그 값을 클라이언트에 돌려준다.
  • Proxy는 실제 서비스의 메서드 호출 전후에도 별도의 로직을 수행할 수 있다.

예시

IService.java

public interface IService {
    String runSystem();
}

Service.java

public class Service implements IService {
    @Override
    public String runSystem() {
        return "시스템을 실행합니다."
    }
}

Proxy.java

public class Proxy implements IService {
    IService service1;

    @Override
    public String runSystem() {
        System.out.println("대신실행 하겠습니다.")
        service1 = new Service();
        return service1.runSystem();
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        IService proxy = new Proxy();
        System.out.println(proxy.runSystem());
    }
}

  • 인터페이스를 두어서 구체 클래스에 영향을 받지 않게 하였음.
  • Proxy를 통해 우회하여 접근하였다.
    • OCP, DIP 원칙이 녹아져있음을 알 수 있다.

Main.java 실행결과

image


디자인패턴 - 전략 패턴 (Strategy Pattern)

  • 객체들이 할 수 있는 행위에 대해 전략 클래스를 생성
  • 유사한 행위들을 캡슐화 하는 인터페이스를 정의
  • 객체의 행위를 동적으로 바꾸고 싶은 경우, 직접 행위를 수정하지 않는다.
  • 전략 클래스를 바꿔주기만 함으로서 행위를 유연하게 확장한다.

예시:

  • Car와 Train은 움직인다는 공통점이 있음. -> Moveable 라는 인터페이스 지정
public interface Moveable {
    public void move();
}
  • Car와 Train 클래스에 move 구현
public class Car implements Moveable {
    public void move() {
        System.out.println("도로로 움직입니다.");
    }
}
public class Train implements Moveable {
    public void move() {
        System.out.println("선로로 움직입니다.");
    }
}
  • Client에 해당 내용을 구현
public class Client {
    public static void main(String args[]) {
        Movable train = new Train();
        Movable car = new Car();

        train.move();
        car.move();
    }
}

  • 이 때, 시간이 흘러 날아다니는 차가 개발되었다고 가정하자.
  • 그래서 Car의 move() 메서드를 다음과 같이 바꾸었다.
public class Car implements Movable {
    public void move() {
        System.out.println("하늘로 날아서 움직입니다.");
    }
}
  • 하지만 이렇게 하면 SOLID의 원칙 중 OCP(Open Closed Principle)을 위배한다.
    • 요구사항의 변경이나 추가사항이 발생하더라도 기존 구성요소는 수정이 일어나지 말아야 한다는 의미.
  • 따라서 전략 패턴을 활용하기 위해 다음처럼 구현한다.

  • MovableStrategy 인터페이스를 생성,
public interface MovableStrategy {
    public void move();
}
  • 그것을 통해 이동수단에 대한 전략들을 구현한다. (이동방법이 확장될 경우를 고려하는 것)
public class RailLoadStrategy implements MovableStrategy {
    public void move() {
        System.out.println("선로로 움직입니다.")
    }
}
public class LoadStrategy implements MovableStrategy {
    public void move() {
        System.out.println("도로로 움직입니다.");
    }
}
public class FlyStrategy implements MovableStrategy {
    public void move() {
        System.out.println("하늘을 날아서 움직입니다.");
    }
}
  • 차와 기차는 move() 메서드를 통해 움직일텐데, 그것을 직접 메서드로 구현하지 않는다.
  • 어떻게 움직일지 전략을 설정하고, 그 전략의 움직임 방식을 사용하여 움직이도록 한다.
  • 그 전략을 설정하는 메서드인 setMovableStrategy() 를 구현한다.
public class Moving {
    private MovableStrategy movableStrategy;

    public void move() {
        movableStrategy.move();
    }

    public void setMovableStrategy(MovableStrategy movableStrategy) {
        this.movableStrategy = movableStrategy;
    }
}
public class Car extends Moving {

}
public class Train extends Moving {

}
  • 그것을 Client로 구현하면 다음과 같다.
public class Client {
    public class void main(String args[]) {
        Moving train = new Train();
        Moving car = new Car();

        train.setMovableStrategy(new RailLoadStrategy());
        car.setMovableStrategy(new LoadStrategy());

        train.move();
        car.move();

        // 여기까지 기차는 선로로 움직이는 것으로, 차는 도로로 움직이는 것으로 설정되었음.
        // 근데 이후에 하늘을 나는 차가 개발됐다고 가정.

        car.setMovableStrategy(new FlyStrategy());
        car.move();
    }
}

  • 이로서, 원래 move() 메서드 코드를 건들이지 않고 행위가 수정되었음.

참고 출처: https://victorydntmd.tistory.com/292

'TIL' 카테고리의 다른 글

URI, URL, URN 차이  (0) 2022.10.25
디자인패턴 - 퍼사드 패턴 (Facade Pattern)  (1) 2022.10.25
객체지향 개발 5대 원리, SOLID  (0) 2022.10.21
동기 vs 비동기, Blocking vs Non-Blocking  (0) 2022.10.19
정규표현식  (0) 2022.10.12

+ Recent posts