관리 메뉴

bright jazz music

Compound Pattern: 1. Adapter패턴 본문

Design Pattern/Compound Pattern

Compound Pattern: 1. Adapter패턴

bright jazz music 2022. 10. 14. 09:27

 여기에 quack하는 기능을 가진 QuackableInterfaceForCompoundPattern 인터페이스가 있다.

//QuackableInterfaceForCompoundPattern

package com.example.designpatternstudy.CompoundPattern;

public interface QuackableInterfaceForCompoundPattern {
    public void quack();
}

 

여러 가지 오리 클래스들이 인터페이스를 구현하여 quack 기능을 오버라이드 한다.

 

MallardDuck, RedheadDuck, 그리고 오리 소리를 낼 수 있는 DuckCall, RubberDuck 역시 QuackableInterfaceForCompoundPattern을 구현하여 저마다의 quack()을 만들 수 있다.

 

//MallardDuck.java

package com.example.designpatternstudy.compoundPattern;
//청둥오리
public class MallardDuck implements QuackableInterfaceForCompoundPattern{

    @Override
    public void quack() {
        System.out.println("꽥꽥");
    }
}
//RedheadDuck.java

package com.example.designpatternstudy.compoundPattern;

public class RedheadDuck implements QuackableInterfaceForCompoundPattern{

    @Override
    public void quack() {
        System.out.println("꽥꽥");
    }
}
//DuckCall.java

package com.example.designpatternstudy.compoundPattern;

public class DuckCall implements QuackableInterfaceForCompoundPattern{
    @Override
    public void quack(){
        System.out.println("꽉꽉");
    }
}
//RubberDuck.java

package com.example.designpatternstudy.compoundPattern;

public class RubberDuck implements QuackableInterfaceForCompoundPattern{
    @Override
    public void quack(){
        System.out.println("삑삑");
    }
}

여기까지는 이름만 다를 뿐 구성은 같은 오리들의 클래스였다.

 

 

그런데 여기 Goose(거위)가 있다. 거위는 quack() 대신 honk() 기능을 가지고 있다. 

//Goose.java

package com.example.designpatternstudy.compoundPattern;
// 거위 추가하기.
public class Goose {
    public void honk(){
        System.out.println("끽끽");
    }
    //시뮬레이터를 사용하기 위해서는 QuackableInterfaceForCompoundPattern를 써야함.
    //그러나 거위는 quack() 대신 honk()를 가지고 있음.
    //따라서 오리 자리에 거위가 들어가 수 있도록 adapter를 사용하자. GooseAdapter.java

}

만약 오리 소리를 테스트하는 DuckSimulator라는 프로그램에서 Goose를 테스트하고자 한다면 어떻게 해야 할까? Goose가 다른 오리 클래스들처럼 QuackableInterfaceForCompountPattern을 직접 구현할 수도 있을 것이다. 그러나 이렇게 해버리면 open-closed principle을 위반하게 된다. 즉, 기존 코드를 수정하게 된다. 이번처럼 프로그램이 간단하다면 기존 코드를 수정해도 문제가 발생하지 않을 수도 있다. 그러나 코드가 복잡하고 방대하다면 이야기가 다르다. 미세한 수정이 프로그램 전체에 치명적인 문제를 야기할 수도 있다.

 

따라서 여기서는 어댑터 패턴을 사용해서 기존 코드의 수정 없이도 새로운 코드가 기존 코드와 호환되도록 만들 수 있다. 어댑터 패턴은 어댑터를 만들어서 코드가 서로 호환되도록 하는 패턴이다. 우리가 전자기기간 호환을 위해 사용하는 젠더를 떠올리면 개념을 이해하기에 수월할 것이다.

 

 

아래는 Goose를 DuckSimulator에서 사용하기 위해 작성한 GooseAdapter 클래스이다

 

//GooseAdapter.java

package com.example.designpatternstudy.compoundPattern;
//Goose를 DuckSimulator를 사용해 시뮬레이션 하기 위해 사용하는 어댑터

//어댑터 클래스에서는 타겟 인터페이스를 구현해야 한다.
// 여기서는 QuackableInterfaceForCompoundPattern이 타겟
public class GooseAdapter implements QuackableInterfaceForCompoundPattern {

    Goose goose;

    //생성자
    public GooseAdapter(Goose goose){
        this.goose = goose;
    }

    @Override
    public void quack() {
        goose.honk();
    }
}
  • GooseAdapter클래스는 다른 오리 클래스들처럼 QuackableInterfaceForCompoundPattern을 구현한다.
  • GooseAdapter클래스는 멤버로서 Goose를 주입받는다.
  • GooseAdapter클래스의 생성자는 Goose클래스를 파라미터로 받는다. 이는 멤버 Goose에 대입된다.
  • GooseAdapter클래스는  자신의 구현하는 인터페이스의 quack()메소드를 오버라이드 한다. quck()안에서의 기능은 Goose에게 위임한다. 

 

 

이제 GooseAdapter가 DuckSimulator에서 동작하는 모습을 보자.

//DuckSimulator.java

package com.example.designpatternstudy.compoundPattern;

public class DuckSimulator {

	//외부에서 이 메소드를 실행하면 DuckSimulator 객체가 생성되고 simulateAll()메서드가 실행된다.
    //즉, 정적 팩토리 메서드의 역할을 한다.
    public static void initDuckSimul(){ 
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulateAll();
    }

    void simulateAll(){
        QuackableInterfaceForCompositePattern mallardDuck = new MallardDuck();
        QuackableInterfaceForCompositePattern redheadDuck = new RedheadDuck();
        QuackableInterfaceForCompositePattern duckCall = new DuckCall();
        QuackableInterfaceForCompositePattern rubberDuck = new RubberDuck();
        //GooseAdapter를 사용해서 오리가 됨
        QuackableInterfaceForCompositePattern gooseDuck = new GooseAdapter(new Goose());

        System.out.println("\n오리 시뮬레이션 게임 (+ 거위 어댑터)");

        simulate(mallardDuck);
        simulate(redheadDuck);
        simulate(duckCall);
        simulate(rubberDuck);
        //거위 시뮬레이트
       simulate(gooseDuck);

    }
	
    void simulate(QuackableInterfaceForCompoundPattern duck){
        duck.quack();
    }


}

복잡할 것이 없다. GooseAdapter 역시 다른 오리들처럼 생성자를 사용하여 클래스의 객체를 생성한다. 그리고 이를 자신이 구현하고 있는 QuackableInterfaceForCompoundPattern으로 업캐스팅 한다. 이를 다시 simulate() 메서드의 파라미터로 대입한다.

 

 

아래는 외부에서 DuckSimulator의 initDuckSimul()을 호출한 경우이다.

//CompositePatternTests.java

package com.example.designpatternstudy;

import com.example.designpatternstudy.compoundPattern.DuckSimulator;
import org.junit.jupiter.api.Test;

public class CompoundPatternTests {


    @Test
    public void duckSimulTest(){

//        DuckSimulator duckSimulator = new DuckSimulator();
//        duckSimulator.initDuckSimul();
// 이렇게 했더니 아래와 같은 경고 발생
//        Static member 'com.example.designpatternstudy.compoundPattern.DuckSimulator.initDuckSimul()' accessed via instance reference
//        Inspection info: Reports references to static methods and fields via a class instance rather than the class itself.
//        Even though referring to static members via instance variables is allowed by The Java Language Specification, this makes the code confusing as the reader may think that the result of the method depends on the instance.
//                The quick-fix replaces the instance variable with the class name.
//        Example:
//        String s1 = s.valueOf(0);
//        After the quick-fix is applied:
//        String s = String.valueOf(0);
//        클래스의 인스턴스를 통해 static 멤버(여기서는 initDuciSimul())에 접근하는 것도 가능하다. 그러나 이는 코드를 헷갈리게 만든다.
//        독자는 해당 메소드의 결과가 객체에 의존적이라고 생각할 수도 있다.
//        ==> 해당 멤버가 static이라면 객체 생성하여 접근할 필요 없이 그냥 클래스로 접근하라는 뜻.

        DuckSimulator.initDuckSimul();
     
        //오리 시뮬레이션 게임 (+ 거위 어댑터)
        //꽥꽥
        //꽥꽥
        //꽉꽉
        //삑삑
        //끽끽


    }

}

정상적으로 "끽끽" 이 출력되는 것을 볼 수 있다.

Comments