본문 바로가기
Programming/Node.js

[디자인 패턴] Strategy Pattern

by BTC_JGT 2022. 10. 25.

전략 패턴

  • 행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀 수 있게 해주는 패턴
  • 같은 문제를 해겨할는 여러 알고리즘이 클래스별로 캡슐화되어 있고 이들이 필요할 때 교체할 수 있도록 함으로써 동일한 문제를 다른 알고리즘으로 해결할 수 있게 하는 디자인 패턴
  • 객체가 할 수 있는 행위들을 각 각의 전략으로 만들어 놓고 동적으로 행위의 수정이 필요한 경우 전략을 바꾼느 것만으로 행위의 수정이 가능하도록 만든 패턴

예시 

public abstract class Device {
    private String name;
    public Device(String name) {this.name = name;}
    public Strng getName() {return this.name;}

    public abstract void print();
    public abstract void input();
}

public class Phone extends Device{
    public Phone(String){super(name);}
    public void print(){/* 터치 액정을 통해 출력*/ }
    public void input(){/* 터치 액정을 통한 입력*/ }
}

public class Computer extends Device{
    public Computer(String){super(name);}
    public void print(){/* 모니터를 통해 출력*/ }
    public void input(){/* 마우스 키보드을 통한 입력*/ }
}

public class Client {
    public static void main(String[] args)
    {
        Device s9 = new Phone("갤9+");
        Device superCom = new Computer("슈퍼컴");

        s9.print(); 
        s9.input();

        superCom.print();
        superCom.input();
    }
}

기존의 객체를 선언하고 객체의 메소드를 이용할때는 위와 같이 사용하였습니다. 하지만 Phone의 메서드 print의 출력을 스피커로 변경하기 위해서는 아래와 같이 클래스를 변경해야 합니다.

public class Phone extedns Device{
    public Phone(String){super(name);}
    public void print(){/* 스피커를 통해 출력*/ }
    public void input(){/* 터치 액정을 통한 입력*/ }
}

하지만 이와 같은 경우는 Solid 법칙 중 OCP(Open-Close Principle)에 위배를 하게되므로 좋은 수정 방법이 아닙니다. 그리고 Phone와 Compute 클래스에 중복되는 코드가 존재합니다.

위와 같은 방법을 해결하는 방법이 전략 패턴입니다.

위 Device 클래스의 input과 print메서드 들이 문제를 발생시키는 요인이 됩니다. 이를 캡슐화하기 위해서는 외부에서 구체적인 print,input를 클래스들로 은닉해야 합니다.

print, input 을 위한 인터페이스를 각자 만들고 이들을 실제 실현한 클래스들을 만들어야합니다.

Device 클래스가 출력, 입력 기능을 이용하는 클라이언트 역할을 수행합니다. PrintingStrategy, InputtingStrategy 인터페이스에 의해 캡슐화가 되었으며 이 인터페이스들이 Device 클래스의 변경을 차단할 수 있습니다.

전략 패턴을 이용하면 새로운 기능의 추가가 기존의 코드 영향을 미치지 않으므로 OCP를 만족하게 됩니다.

위 처럼 변화된 구조에서는 외부에서 출력,입력 기능을 임의대로 수정하기 위해서는 setter 메서드가 필요합니다.

public abstract class Device {
    private String name;
    private PrintingStrategy printingStrategy;
    private InputtingStrategy inputtingStrategy;

    public Device(String name) {this.name = name;}
    public Strng getName() {return this.name;}

    public void print() { printingStrategy.print();}
    public void input() { inputtingStrategy.input();}
    
    public void setInputtingStrategy(InputtingStrategy inputtingStrategy){
        this.inputtingStrategy = inputtingStrategy;
    }
    public void setPrintingStrategy(PrintingStrategy printingStrategy){
        this.printingStrategy = printingStrategy;
    }
}

interface PrintingStrategy{public void print();}

public class MonitorStrategy implements PrintingStrategy {
    public void print() {/* 모니터로 출력 */}
}
public class SpeakerStrategy implements PrintingStrategy {
    public void print() {/* 스피커로 출력 */}
}

interface InputtingStrategy{public void input();}
public class TouchPannelStrategy implements InputtingStrategy {
public void input() {/* 터치패널로로 입력 */}
}
public class MouseKeyboardStrategy implements InputtingStrategy {
public void input() {/* 마우스,키보드로 입력 */}
}

public class Phone extends Device{
    public Phone(String){super(name);}
}

public class Computer extends Device{
    public Computer(String){super(name);}
}

public class Client {
    public static void main(String[] args)
    {
        Device s9 = new Phone("갤9+");
        Device superCom = new Computer("슈퍼컴");

        s9.setInputtingStrategy(new TouchPannelStrategy());
        s9.setPrintingStrategy(new MonitorStrategy());


        superCom.setInputtingStrategy(new MouseKeyboardStrategy());
        superCom.setPrintingStrategy(new SpeakerStrategy());

        s9.print(); // 모니터로 출력
        s9.input(); // 터치 패널로 입력

        superCom.print(); // 스피커로 출력
        superCom.input(); // 마우스키보드로 입력
    }
}

References

'Programming > Node.js' 카테고리의 다른 글

[JAVA] SubnetUtils  (0) 2022.12.06
Java Casting (형변환)  (0) 2022.11.30
싱글톤 (Singleton) 패턴  (0) 2022.10.21
[Spring] 컨테이너 빈 이름으로 조회하기  (0) 2022.10.12
[JAVA] this  (0) 2022.10.11

댓글