thumbnail

커맨트 패턴이란?

커맨드 패턴은 이벤트가 발생했을때 실행될 기능이 다양하면서도 변경이 필요한 경우에,

이벤트를 발생시키는 클래스를 변경하지 않고 재사용하고자 할 때 유용하다.

<br/>

이해하기 어려우니 예를 들어보자.

"파일열기", "파일닫기"라는 메뉴 항목이 있다.

각 항목이 선택되었을때 실행 되는 기능이 다를 것이다.

각 기능을 구현하기위해 "메뉴" 클래스에 파일열기 기능을 구현하였다

각 기능을 구현하기위해 "메뉴" 클래스에 파일닫기 기능을 구현하였다

<br/>

근데 고객이 메뉴에 "파일추가" 기능을 추가 할 것을 요청했다.

추가된 기능을 구현하기위해 "메뉴" 클래스에 파일추가 기능을 구현하였다.

"메뉴"클래스에 참조값을 늘렸고, "메뉴"클래스를 수정하게 되었다.

즉 "메뉴" 클래스는 재사용 할 수 없었다.

<br/>

커맨트 패턴은 "메뉴"클래스를 재사용하게 하는데 유용하다.

N번의 고객의 추가 기능 요청해도 수정없이, 재사용 할 수 있도록 하게 하는 것이다.

커맨드 패턴은 기능을 요구하는 호출자 클래스와 실제 기능을 수행하는 "수신자" 클래스의 의존성을 제거 한다.

<br/>

예를 통해 구현해보자.

만능 버튼을 만들려고하는 고객의 요청이 생겼다.

만능 버튼에 기능으로, 버튼이 눌렸을때 램프의 전원 ON 기능을 요청하였다.

개발자는 다음과 같이 클래스 구조를 설계하였다.

<img src="https://static.podo-dev.com/blogs/images/2019/07/10/origin/F51T4F181224235507.PNG">

  • 버튼 클래스

  • 램프 클래스

<br/>

버튼을 누르면, 램프를 켜야하므로 Button클래스는 Lamp 클래스를 참조한다.

<br/>

다음과 같이 구현하였다.

public class Button {
	private Lamp theLamp;

	public Button(Lamp theLamp) {
		super();
		this.theLamp = theLamp;
	}

	public void pressed() {
		theLamp.turnOn();
	}
}
<br/>
public class Lamp {
	public void turnOn() {
		System.out.println("램프에 전원이 켜졌습니다.");
	}
}
public class Main {
	public static void main(String[] args) {
		Lamp theLamp = new Lamp();
		Button button = new Button(theLamp);

		button.pressed();
	}
}
<br/>

<br/>

출력값

램프에 전원이 켜졌습니다.
<br/>

정상적으로 로직이 구동되어, 정상 출력하였다.

<br/>

그러나 고객의 추가적인 요구사항이 생겼다.

"만능 버튼이니까, 버튼을 누르면 알람 켜주는 기능도 넣어주세요!"

<br/>

개발자는 요청사항을 받아들여 다음과 같이 설계하였다.

<img src="https://static.podo-dev.com/blogs/images/2019/07/10/origin/XVSMXB181224235507.PNG">

  • 버튼 클래스

  • 램프 클래스

  • 알람 클래스

<br/>

<br/>

버튼을 누르면, 램프를 켜야하므로 Button클래스는 Lamp 클래스를 참조한다.

버튼을 누르면, 알람을 켜야하므로 Button클래스는 Alarm 클래스를 참조한다.

<br/>

다음과 같이 구현하였다.

public enum Mode {
	LAMP, ALARM;
}
<br/>
public class Button {
	private Lamp theLamp;
	private Alarm theAlarm;
	private Mode theMode;

	public Button(Lamp theLamp, Alarm theAlarm) {
		this.theLamp = theLamp;
		this.theAlarm = theAlarm;
	}

	public void setTheMode(Mode theMode) {
		this.theMode = theMode;
	}

	public void pressed() {
		switch (theMode) {
		case LAMP:
			theLamp.turnOn();
			break;
		case ALARM:
			theAlarm.start();
			break;
		}

	}
}
public class Alarm {
	public void start() {
		System.out.println("알람이 켜졌습니다.");
	}

}
public class Lamp {
	public void turnOn() {
		System.out.println("램프에 전원이 켜졌습니다.");
	}
}
public class Main {
	public static void main(String[] args) {
		Lamp theLamp = new Lamp();
		Alarm theAlarm = new Alarm();
		Button button = new Button(theLamp, theAlarm);
		
		button.setTheMode(Mode.LAMP);
		button.pressed();
		
		button.setTheMode(Mode.ALARM);
		button.pressed();

	}
}
<br/>

<br/>

출력값

램프에 전원이 켜졌습니다.
알람이 켜졌습니다.

요구에 맞게 정상적으로 로직이 구동되어, 정상 출력하였다.

<br/>

그러나 고객은 다음의 요구를 더 요청하였다.

"만능 버튼이니까, 램프 끄는 기능, 알람 끄는 기능도 추가해주세요!"

<br/>

개발자는 고민하였다. 앞으로 고객이 만능버튼이라고 기능을 계속 요청할 것이다.

버튼 클래스에 기능을 계속구현하여 N개의 값에 스위치문으로 N개를 구분할 수는 없다.

또 N개의 기능이 추가되면 N번의 Button클래스를 수정해야 할지도 모른다.

따라서 디자인패턴 중** 커맨드 패턴**을 이용하려고한다.

<br/>

개발자는 다음과 같이 클래스 구조를 설계하였다.

<img src="https://static.podo-dev.com/blogs/images/2019/07/10/origin/RAZX8K181224235507.PNG">

  • Button클래스는 Command 인터페이스를 참조한다.

<br/>

각 기능들은 Command 인터페이스를 상속받아 excute() 메소드를 구현한다.

이제 N개의 기능이 추가되더라도, Button 클래스는 수정하지 않아도 될것이다.

또한 호출클래스인 Button 클래스와, 수신클래스인 Lamp클래스와의 의존도 또한 제거되었다.

<br/>

다음과 같이 구현하였다.

public class Button {
	private Command theCommand;

	public void setTheCommand(Command theCommand) {
		this.theCommand = theCommand;
	}

	public void pressed() {
		theCommand.excute();
	}
}
public class Alarm {
	public void start() {
		System.out.println("알람이 켜졌습니다.");
	}
	
	public void stop() {
		System.out.println("알람이 꺼졌습니다.");
	}
}
public class Lamp {
	public void turnOn() {
		System.out.println("램프에 전원이 켜졌습니다.");
	}
	
	public void turnOff() {
		System.out.println("램프에 전원이 꺼졌습니다.");
	}
}
public interface Command {
	public void excute();
}
<br/>
public class AlarmStartCommand implements Command {
	private Alarm theAlarm;

	public AlarmStartCommand(Alarm theAlarm) {
		this.theAlarm = theAlarm;
	}

	@Override
	public void excute() {
		theAlarm.start();
	}

}
<br/>
public class AlarmStopCommand implements Command {
	private Alarm theAlarm;

	public AlarmStopCommand(Alarm theAlarm) {
		this.theAlarm = theAlarm;
	}

	@Override
	public void excute() {
		theAlarm.stop();
	}

}
public class LampOnCommand implements Command {
	private Lamp theLamp;

	public LampOnCommand(Lamp theLamp) {
		this.theLamp = theLamp;
	}

	@Override
	public void excute() {
		theLamp.turnOn();
	}

}
<br/>
public class LampOffCommand implements Command {
	private Lamp theLamp;

	public LampOffCommand(Lamp theLamp) {
		this.theLamp = theLamp;
	}

	@Override
	public void excute() {
		theLamp.turnOff();
	}

}
<br/>
public class Main {
	public static void main(String[] args) {
		Lamp theLamp = new Lamp();
		Alarm theAlarm = new Alarm();
		Button button = new Button();

		button.setTheCommand(new LampOnCommand(theLamp));
		button.pressed();

		button.setTheCommand(new LampOffCommand(theLamp));
		button.pressed();

		button.setTheCommand(new AlarmStartCommand(theAlarm));
		button.pressed();

		button.setTheCommand(new AlarmStopCommand(theAlarm));
		button.pressed();

	}
}

<br/>

출력값

램프에 전원이 켜졌습니다.
램프에 전원이 꺼졌습니다.
알람이 켜졌습니다.
알람이 꺼졌습니다.
<br/>

<br/>
<br/>

CommentCount 0
이전 댓글 보기
등록
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
TOP