Command pattern
using System.Text;
#region Base
public interface Command
{
public void Execute() { }
public void Undo() { }
}
public class Light
{
public void On() { Console.WriteLine("Light is on"); }
public void Off() { Console.WriteLine("Light is off"); }
}
public class GarageDoor
{
public void Up() { Console.WriteLine("Garage door is up"); }
public void Down() { Console.WriteLine("Garage door is down"); }
public void Stop() { Console.WriteLine("Garage door is stopped"); }
public void LightOn() { Console.WriteLine("Garage door light is on"); }
public void LightOff() { Console.WriteLine("Garage door light is off"); }
}
public class Stereo
{
public void On() { Console.WriteLine("Stereo is on"); }
public void Off() { Console.WriteLine("Stereo is off"); }
public void SetCd() { Console.WriteLine("Stereo is set for CD input"); }
public void SetVolume(int volume) { Console.WriteLine($"Stereo is set to {volume} volume"); }
}
#endregion
#region Command
public class NoCommand : Command
{
//Null 객체
public void Execute() { }
}
public class LightOnCommand : Command
{
private Light light;
public LightOnCommand(Light l) { this.light = l; }
public void Execute() { light.On(); }
public void Undo() { light.Off(); }
}
public class LightOffCommand : Command
{
private Light l;
public LightOffCommand(Light l) { this.l = l; }
public void Execute() { l.Off(); }
public void Undo() { l.On(); }
}
public class GarageDoorCommand : Command
{
private GarageDoor door;
public GarageDoorCommand(GarageDoor d) { this.door = d; }
public void Execute() { door.Up(); door.LightOn(); }
public void Undo() { door.Down(); door.LightOff(); }
}
public class StereoOnWithCDCommand : Command
{
private Stereo stereo;
public StereoOnWithCDCommand(Stereo s) { this.stereo = s; }
public void Execute() { stereo.On(); stereo.SetCd(); stereo.SetVolume(11); }
public void Undo() { stereo.Off(); }
}
#endregion
public class RemoteControl
{
private Command undoCommand;
private Command[] onCommands;
private Command[] offCommands;
public RemoteControl()
{
int index = 7;
onCommands = new Command[index];
offCommands = new Command[index];
NoCommand c = new NoCommand();
for(int i = 0; i < index; i++)
{
onCommands[i] = c;
offCommands[i] = c;
}
undoCommand = c;
}
public void SetCommand(int slot, Command onCommand, Command offCommand)
{
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void SetCommand(int slot, Command onCommand)
{
onCommands[slot] = onCommand;
}
public void OnBtnPressed(int slot) { onCommands[slot].Execute(); undoCommand = onCommands[slot]; }
public void OffBtnPressed(int slot) { offCommands[slot].Execute(); undoCommand = offCommands[slot]; }
public void UndoBtnPressed() { undoCommand.Undo(); }
public StringBuilder GenerateRemoteLog()
{
StringBuilder sb = new StringBuilder();
sb.Append("\n------------RemoteControl-------------\n");
for(int i = 0; i < onCommands.Length; i++)
{
sb.Append($"Slot {i} : {onCommands[i].GetType().Name} {offCommands[i].GetType().Name} \n");
}
sb.Append($"Undo : {undoCommand.GetType().Name}");
return sb;
}
}
public class RemoteControlTest
{
public static void Main(string[] args)
{
RemoteControl remote = new RemoteControl();
Light light = new Light();
GarageDoor door = new GarageDoor();
Stereo stereo = new Stereo();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
Command garageDoorUpCommand = new GarageDoorCommand(door);
Command stereoOnWithCDCommand = new StereoOnWithCDCommand(stereo);
remote.SetCommand(0, lightOnCommand, lightOffCommand);
remote.SetCommand(1, garageDoorUpCommand);
remote.SetCommand(2, stereoOnWithCDCommand);
Console.WriteLine(remote.GenerateRemoteLog().ToString());
remote.OnBtnPressed(0);
remote.OffBtnPressed(0);
remote.UndoBtnPressed();
remote.OnBtnPressed(1);
remote.OnBtnPressed(2);
remote.UndoBtnPressed();
Console.WriteLine("----------------------------------");
Console.WriteLine(remote.GenerateRemoteLog().ToString());
}
}
구상 커맨드 객체를 줄이려면 람다를 사용한다.
public class Command
{
private readonly Action _execute;
public Command(Action execute)
{
_execute = execute;
}
public virtual void Execute()
{
_execute();
}
}
public class NoCommand : Command
{
//Null 객체
public NoCommand(Action execute) : base(execute) { }
}
//외에 커맨드 구상 객체는 삭제한다.
remote.SetCommand(0, new Command(() => light.On()), new Command(() => light.Off()));
remote.SetCommand(1, new Command(() => { door.Up(); door.LightOn(); }));
remote.SetCommand(2, new Command(() => { stereo.On(); stereo.SetCd(); stereo.SetVolume(11); }));
이왕 람다식 사용한 거 구상클래스들 싹 지우고 타입 통일했다.
근데 추가적인 기능이 필요하다면 그냥 두는 게 나을 것 같다.
'코딩 공부 > 디자인패턴' 카테고리의 다른 글
템플릿 메소드 패턴 (0) | 2024.12.05 |
---|---|
어댑터 패턴, 퍼사드 패턴 (1) | 2024.12.04 |
팩토리 패턴 (0) | 2024.12.03 |
데코레이터 패턴 (0) | 2024.12.03 |
옵저버 패턴 (0) | 2024.12.03 |