동작하는 메소드를 클래스로 제작하여 캡슐화시킨 패턴입니다.
행동 패턴(Behavioral Design Patterns)중 하나이죠.
장점
- 런타임 중(실행 중)에 동적으로 사용되는 알고리즘을 변경할 수 있습니다.
- 단일/책임 원칙을 만족하며 작업을 호출하는 클래스(Invoker)와 작업을 수행하는 클래스(Receiver)를 분리 할 수 있습니다.
- 실행/취소를 구현할 수 있습니다.
- 개방/폐쇄 원칙을 만족하며 새로운 커맨드를 추가해 기능을 추가할 수 있습니다.
단점
- Receiver와 Invoker사이에 있는 Command를 계속 추가하는 것이기에 코드가 더 복잡해질 수 있습니다.
C#으로 Console 프로젝트를 하나 생성해서 할 것입니다.
매우 심플하게 만들 것이죠.
목표는 Main에서 "calculater"라는 변수를 통한 다양한 연산 결과를 출력입니다.
프로젝트의 tree구조는 아래와 같습니다.
Command (Project)
|- Program.cs (Main)
|- Phone.cs (Receiver)
|- RemoteController.cs (Invoker)
|- ICommand.cs (Command Interface)
|- PhoneTurnOnCommand.cs (Command)
|- PhoneTurnOffCommand.cs (Command)
Phone.cs
using System;
namespace Command
{
public class Phone
{
public string name;
public Phone(string name)
{
this.name = name;
}
public void TurnOff()
{
Console.WriteLine($"[{name}] Turn off");
}
public void UndoTurnOff()
{
Console.WriteLine($"[{name}] undo(Turn off)");
}
public void RedoTurnOff()
{
Console.WriteLine($"[{name}] redo(Turn off)");
}
public void TurnOn()
{
Console.WriteLine($"[{name}] Turn on");
}
public void UndoTurnOn()
{
Console.WriteLine($"[{name}] undo(Turn on)");
}
public void RedoTurnOn()
{
Console.WriteLine($"[{name}] redo(Turn on)");
}
}
}
저는 TurnOn, Off 두개에 대해 일반 이벤트와 Undo, Redo를 구성했으나 매개변수로 각 이벤트를 구별하거나 원하시는대로 따로 처리하시면 됩니다.
ICommand.cs
namespace Command
{
public interface ICommand
{
void Execute();
void Undo();
void Redo();
}
}
실행, 실행 취소, 재실행을 사용할 수 있도록 구성해줍니다.
PhoneTurnOnCommand.cs
namespace Command
{
public class PhoneTurnOnCommand : ICommand
{
private Phone phone;
public PhoneTurnOnCommand(Phone phone)
{
this.phone = phone;
}
public void Execute()
{
phone.TurnOn();
}
public void Redo()
{
phone.RedoTurnOn();
}
public void Undo()
{
phone.UndoTurnOn();
}
}
}
TurnOnCommand에 대한 메소드들을 구현해줍니다.
PhoneTurnOffCommand.cs
namespace Command
{
public class PhoneTurnOffCommand : ICommand
{
private Phone phone;
public PhoneTurnOffCommand(Phone phone)
{
this.phone = phone;
}
public void Execute()
{
phone.TurnOff();
}
public void Redo()
{
phone.RedoTurnOff();
}
public void Undo()
{
phone.UndoTurnOff();
}
}
}
TurnOff 또한 동일하게 구성해줍니다.
RemoteController.cs
using System;
using System.Collections.Generic;
namespace Command
{
public class RemoteController
{
private List<ICommand> undoCommands = new List<ICommand>();
private List<ICommand> redoCommands = new List<ICommand>();
private ICommand command;
public void SetCommand(ICommand command)
{
this.command = command;
}
public void Execute()
{
undoCommands.Add(command);
command.Execute();
}
public void Undo()
{
if (undoCommands.Count - 1 < 0) throw new IndexOutOfRangeException();
ICommand command = undoCommands[undoCommands.Count - 1];
command.Undo();
undoCommands.Remove(command);
redoCommands.Add(command);
}
public void Redo()
{
if (redoCommands.Count - 1 < 0) throw new IndexOutOfRangeException();
ICommand command = redoCommands[redoCommands.Count - 1];
command.Redo();
redoCommands.Remove(command);
undoCommands.Add(command);
}
}
}
redo, undo가 가능하게 List를 만들어준다.
Command를 Set하는 메소드와 실행, 실행취소, 재실행를 구현해줍니다.
실행 취소와 재실행은 배열 길이를 체크하고 더이상 작업이 없을 경우 에러를 내보내게 구현했습니다.
Program.cs
namespace Command
{
class Program
{
static void Main(string[] args)
{
RemoteController remoteController = new RemoteController();
Phone phone = new Phone("android");
PhoneTurnOnCommand turnOn = new PhoneTurnOnCommand(phone);
PhoneTurnOffCommand turnOff = new PhoneTurnOffCommand(phone);
remoteController.SetCommand(turnOn);
remoteController.Execute();
remoteController.SetCommand(turnOff);
remoteController.Execute();
remoteController.Undo();
remoteController.Undo();
remoteController.Redo();
remoteController.Redo();
}
}
}
각 클래스의 인스턴스를 만들고 turnOn을 Set하고 Execute를 해줍니다.
동일하게 turnOff를 함으로 Turn On하고 Turn Off가 출력되야 합니다.
이후에 undo 두번하고 redo두번함으로 역순으로 Undo Off, Undo On이 출력되고 Redo 두번으로 재실행해줍니다.
그렇게 출력된 실행 결과를 확인해면
다 정상적으로 출력됨을 확인할 수 있습니다.
익혀두시면 편리하게 쓰실 수 있습니다.
'Design Pattern' 카테고리의 다른 글
[Design Pattern] 9. Visitor Pattern(방문자 패턴) C# (0) | 2023.03.29 |
---|---|
[Design Pattern] 8. Tamplate Method Pattern(탬플릿 메소드 패턴) C# (0) | 2023.03.28 |
[Design Pattern] 6. Mediator Pattern(중재자 패턴) C# (0) | 2023.03.26 |
[Design Pattern] 5. Observer Pattern(옵저버 패턴) C# (0) | 2023.03.25 |
[Design Pattern] 4. State Pattern(상태 패턴) C# (0) | 2023.03.24 |