코딩 공부/디자인패턴

커맨드 패턴

공부를 함 2024. 12. 4. 15:41

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