2022. 3. 21. 00:00ㆍCSharp/Design Pattern
요청을 객체의 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 이용할 수 있도록 매서드 이름, 매개변수 등 요청에 필요한 정보를 저장 또는 로깅, 취소할 수 있게 하는 패턴이다
문제점
Button 을 만들었다고 가정해 보자
이 Button 의 종류가 여러가지가 있고 각각이 비슷해 보이지만 다른 기능을 수행 한다고 하자.가장 간단한 해결책은 버튼별로 하위 클래스 를 만드는 것이다.이러한 하위 클래스는 버튼 클릭시 실행되어야 하는 코드가 포함된다.
이런 형태가 되게 되면 기본 class ( Button) 의 코드가 변경되었을때 하위 클래스의 코드가 영향을 받게될 가능 성이 있다.
일부 작업들 (복사 / 붙혀넣기) 은 여러 위치에서 호출될 수 있다.
복사 도구모음복사 버튼복사 context menuCtrl+C 키보드
이렇게 코드를 복제하거나 버튼에 종속된 메뉴를 만들어야 하는 경우가 생긴다.
이는 코드에 복잡성을 증가시켜 유지 보수가 힘든 코드의 원인이 된다.
해결책
호출되는 개체, 메서드 이름 및 인수 목록과 같은 모든 요청 정보를
이 요청을 트리거 하는 단일 메서드가 있는 별도의 command class 로 추출해야 한다.
다음 단계는 이 command (명령) 가 동일한 인터페이스를 구현 하도록 하는 것
이 인터페이스를 사용하면 구체적인 명령 클래스에 연결하지 않고도
동일한 요청 발신자와 함께 다양한 명령을 사용할 수 있다.
class diagram
적용
- 작업으로 개체를 매개변수화하려는 경우
- 작업을 대기열에 넣거나 실행을 예약하거나 원격으로 실행하려는 경우
- 되돌릴 수 있는 작업을 구현하려는 경우
Invoker(sender)
: 요청의 시작, 명령 개체에 대한 참조를 저장,
요청을 수신자에게 직접 보내는 대신 해당 명령을 트리거
일반적으로 생성자를 통해 클라이언트에서 미리 생성된 명령을 받는다.
Command(interface)
: 일반적으로 명령을 실행하기 위한 단일 메서드만 선언 (execute)
ConcreateCommand
: 다양한 종류의 요청을 구현 구체적인 명령은 자체적으로 작업을 수행하는 것이 아니라 비즈니스 논리 개체 중 하나로 호출을 전달해야 한다. 그러나 코드를 단순화하기 위해 이러한 클래스를 병합할 수 있다.
수신 개체에서 메서드를 실행하는 데 필요한 매개 변수는 구체적인 명령의 필드로 선언할 수 있다. 생성자를 통해서만 이러한 필드의 초기화를 허용하여 명령 개체를 변경할 수 없도록 만든다.
Receiver
:클래스에는 몇 가지 비즈니스 로직이 포함되어 있다.
거의 모든 개체가 수신기 역할을 할 수 있다.
실제 작업을 수행
공격과 방어를 command 로 처리 해 보자
Command 및 Receiver 구현
public interface ICommand
{
void Execute();
}
public class AttackCommand : ICommand
{
private readonly AttackCommandReceiver _receiver;
private readonly int _attackPower;
private readonly int _attackCount;
public AttackCommand(AttackCommandReceiver receiver, int attackPower, int attackCount)
{
_receiver = receiver;
_attackPower = attackPower;
_attackCount = attackCount;
}
public void Execute()
{
_receiver.Handle(_attackPower, _attackCount);
}
}
public class AttackCommandReceiver
{
public void Handle(int attackPower, int attackCount)
{
Console.WriteLine($"{attackPower} 공격력으로 {attackCount} 번 공격");
}
}
public class DefenceCommand : ICommand
{
private readonly DefenceCommandReceiver _receiver;
private readonly double _defenceRate;
public DefenceCommand(DefenceCommandReceiver receiver, double defenceRate)
{
_receiver = receiver;
_defenceRate = defenceRate;
}
public void Execute()
{
_receiver.Handle(_defenceRate);
}
}
public class DefenceCommandReceiver
{
public void Handle(double defenceRate)
{
Console.WriteLine($"{defenceRate * 100} % 확률로 방어");
}
}
Invoker 구현
public class UnitInvoker
{
private ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void MoveAfterAction()
{
Console.WriteLine("앞으로 한칸 이동 후 ");
_command.Execute();
}
}
사용법
UnitInvoker invoker = new UnitInvoker();
invoker.SetCommand(new AttackCommand(new AttackCommandReceiver(), 10, 5));
invoker.MoveAfterAction();
invoker.SetCommand(new DefenceCommand(new DefenceCommandReceiver(), 0.5));
invoker.MoveAfterAction();
//output
앞으로 한칸 이동 후
10 공격력으로 5 번 공격
앞으로 한칸 이동 후
50 % 확률로 방어
관련영상
'CSharp > Design Pattern' 카테고리의 다른 글
Observer (0) | 2022.03.23 |
---|---|
Mediator (0) | 2022.03.22 |
Template Method (0) | 2022.03.18 |
State (0) | 2022.03.17 |
Memento (0) | 2022.03.16 |