ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디자인 패턴 (7) - 커맨드 패턴
    언어/디자인패턴 2023. 9. 12. 11:31

     

    1. 커맨드 패턴이란?

     

    - 실행될 기능을 캡슐화하여 여러 기능을 실행할 수 있는 재사용성이 높은 클래스 설계 패턴

    - 이벤트가 발생했을 때 실행될 기능이 다양+변경 가능성이 있을때, 이벤트 발생 클래스 변경하지 않고 재사용

    - 행위 패턴 중 하나이다.

    - 실행할 기능 캡슐화하여 실행 요구 호출자(클라이언트)클래스와 실제 기능 수신자 클래스 의존성 제거

    - 실행될 기능이 변경되어도 호출자 클래스에 어떠한 수정 없이 그대로 사용가능

     

     

    1.1 커맨드 패턴의 구조 

     

    출처:https://gmlwjd9405.github.io/2018/07/07/command-pattern.html

    - Command : 실행될 기능에 대한 인터페이스 

    - ConcreteCommand: 실제 실행되는 기능 구현

    - Invoker : 기능의 실행을 요청하는 호출자 클래스

    - Receiver: ConcreteCommand에서 execute 메서드 구현시 필요한 클래스 

                      즉, ConcreteCommand 기능 실행하기 위해 사용됨

     

    * 클라이언트가 커맨드를 만든다 -> 인보커에 set커맨드한다 -> 인보커는 커맨드는 execute를 호출 ->

    execute된 콘크리트 커맨드는 구성된 객체 메서드 호출  

     

    *일련의 행동을 특정 리시버와 연결하여 요청을 캡슐화 (객체를 서로 다른 요청에 따른 매개변수화)

     

     

    2. 만능버튼 만들기 (예시1)

     

    public class Lamp{
    	public void turnOn(){//램프켜짐}
    }
    
    //버튼을 누르면 램프의 불이 켜짐 
    public class Button{ //호출자
     private Lamp lamp;
     public Button(Lamp la) {this.lamp = la;}
     public void pressed(){
     	la.trunOn();
     }
    }
    
    public class Client{
    	public static void main(String[] args){
        	Lamp lamp = new Lamp();
            Button lampButton = new Button(lamp);
            lampButton.pressed();
        }
    
    }

    - Button을 눌렀을 때 불이 켜지는 이벤트 

     

    2.1 문제점 

     

    1. 버튼을 눌렀을 때 다른 기능을 실행하는 경우 

    ex 버튼 눌렀을 때 알람이 시작되게 하려면?

    public class Alarm{
    	public void start(){
        	//알람울림
        }
    }
    
    public class Button{
    	private Alarm alarm;
        public Button(Alarm al){this.alarm = al;}
    	public void pressed() {alarm.start();}
    }

     - 새로운 기능이 추가되면, 기존 Button내용을 수정해야함 

     

    2. 버튼을 누르는 동작에 따라 다른 기능 실행해야하는 경우 (이게 포인트)

    public class Button{
    	private Lamp lamp;
        private Alarm al;
        
        public Button() //램프와 알람을 생성자에서 받음
        
        public void pressed(String mode){
        	//mode에따라 lamp에 불을 켜거나 알람을 울림 
            //새로운 기능이 추가되면, 버튼을 수정해야함 
            //따라서 OCP위배
        }
    
    }

     

    2.2 커맨드패턴 적용

     

    - 기능-> 버튼 눌렀을 때 이벤트가 변화가능성이 있다 -> 캡슐화 

    - Button클래스의 pressed메서드 구체적 기능을 직접구현하지 않고, 캡슐화된 기능을 외부에서 제공받아서 

      위임하자!

    출처:https://gmlwjd9405.github.io/2018/07/07/command-pattern.html

    - Button클래스는 Command 인터페이스를 구성하고 execute를 호출

    - LampOnCommand는 램프 온되도록 execute를 구현

    - AlarmStartCommand는 알람이 켜지도록 구성 

     

    > Command와 Button

    public interface Command{
    	public void execute();
    }
    
    public class Button{
    	private Command co;
        public Button(Command co) {
        
        setCommand(co);
        
        }
        public void setCommand(command newCommand){
        	this.co = newCommand;
        } 
        
        public void pressed(){
        	co.execute();
        }
    
    }

    -Lamp와 LampOnCommand

    public class Lamp{
    
    	public void turnOn(){//}
    
    }
    
    public class LampOnCommand implements Command{
    	private Lamp lamp;
        public LampOnCommand(Lamp la){
        	this.lamp=la;
        }
        public void execute(){
        	lamp.turnOn();
        }
    }

    - Client

    public class Client{
    
    public static void main(String[] args){
    	Lamp lamp = new Lamp();
        Command lampOnCommand = new LampOnCOmmand(lamp);
        Button button1 = new Button(lampOnCommand);
        button1.pressed();
    
    }
    
    }

     

    *Invoker는 커맨드를 가지고 있고, 커맨드는 Receiver를 구성함 

     -> 커맨드를 호출하면, 커맨드가 콘크리트가 구성한 Receiver의 메서드를 호출 

     

    * 전략패턴은 보통 최상위 Abstract클래스가 전략인터페이스와 전략을 수정할 방법을 가지고 있고,

      새로운 구체 클래스를 만든 후 전략을 수정함 (추상화된 놈이 초기 전략 가짐 -> 구체는 경우에 따라 수정)

    * 커맨드 패턴은 특정 클래스에서 전략 인터페이스를 사용하는데, 구체 전략에 따라 전략과 관련된 클래스가 맵핑되는 느낌 이런차이 아닐까?

Designed by Tistory.