커맨드패턴
아이디어. 우리는 리모컨만 쓰고싶어. 슬롯은 On/Off 라는 정규 기능만 수행하면 돼
이런 인터페이스를 커맨드 인터페이스라고 하고, On/Off만 각각 구현해 준 인풋과 아웃풋을 설계하자.
재사용이 가능해지고 뭐가 실행되는지 몰라도 된다!
그냥 A.On, A.Off 가 되겠지뭐!
너무예쁘다. 버튼은 excute() 만 한다. On버튼도, Off버튼도.
버튼의 역할은 그냥 눌리는것. 끝
Off 버튼이 아무것도 없는 그냥 고무덩어리일 뿐이여도 상관없다.
전임자가 이 기계는 꺼지면 안돼서 그냥 빼버렸나보지! 라고 생각하면 되는것.
우리는 고객. 주방에서 햄버거를 ‘어떻게’ 조리할지(실행) 는 몰라도 됨. 그냥 API 가져다 쓰는거니까!
우리는 그래서 웨이터한테 이거 이거 이거 실행! 만 주문서(커맨드)를 한장 써서(Create) 전달해 주면 끝이다.
이 웨이터는 주문서를 들고 주방장에게 주문서를 해석(디코딩)해 준다.
커맨드는 인터페이스인데 리시버와 행동 정보가 들어있음.
인보커(웨이터)는 전달받은 커멘드를Set하고 리시버에 가기 전까지 그냥 보관함.
리시버에 도착하면 커맨드의 excute() 를 그냥 실행해 줌. 끝임
주방장이 못알아들었다? 내잘못 아니야. 클라이언트가 잘못 주문했나보지
반대로, 클라이언트가 주문 똑바로 했는데 왜안나와?
웨이터 잘못 아니야! 주방장이 아픈가보지!
책임 소재가 명확해 진다.

인보커는 전달자, 스레드에 끼어들어서 실행해주는 친구.
얘한테 커맨트 인터페이스의 구상커맨드 객체를 주면, Set 했다가 올바른 리시버에게 가서
커맨드의 excute()만 전달해 준다.
커맨드에는 행동과 리시버 정보가 있고, 외부로 노출된 건 excute()밖에 없다.
주문서에 표지가 덮혀있어서 못보는거라고 생각하자
리모컨에는 슬롯이 있고
슬롯에 커맨드를 할당한다 리시버(형광등,오븐,에어컨),행동(켜기,끄기,Undo),excute()가 되겠지.
위 리모콘은 한 10개 버튼 있었나? 리모컨 클래스 : implements ICommand 해서 slots[10]개 = new commnad[] 하고
각각 버튼은 nullexcute()를 할당해놓고 나중에 on이나 off로 재할당 해주면 됨
여기서 더미코드 박는건 Stub 이라고 하는데, 몽키테스트같은거 할때 안멈추게 하려고 일단 그냥 Log(“NULL입니다.“)이런거
보면 구상커맨드녀석들 라이트라는 리시버에 대해 excute()안에 각각 이름에 걸맞는 행동이 실행되도록 구현됨
타겟은 오리. 꽥On=꽥, 꽥Off=…꽥? 이렇게 그냥 동일리시버의 기능을 분리해서 버튼 하나에 할당해준것.
아주 많이 볼 수 있다. 단순히 그림판만 가봐도 기능 하나 선택하고 우클릭하면? 점 그리기, 전체색칠하기, 스프레이뿌리기 등
한번에 한가지 기능을 직관적으로 쓸 수 있게 버튼화 함.
마지막에 실행한 기능의 반대 기능을 저장해서 스왑해주면 됨
이거 여러번 하고싶다? 그냥 UNDO의 커맨드를 스택으로 만들어서
뭐 실행할 때 마다 넣어주면 됨.
포토샵같은건 이거 마지막 실행 되돌리기 50번인가가 디폴트고 계속 늘릴 수 있는데
대신 메모리 엄청 잡아먹는다.
또 한가지 트릭으로는, On,Off와 선풍기 바람 약하게, 중간, 강하게 가 있으면
On, Off + 파라미터로 약,중,강 을 설정하는 게 아니라
On에다가만 약하게On 중간On 강하게On 을 만들고
Off는 그냥 하나만 만들어서 모두 공유해 버리면 됨!
이러면 버튼 네개로 끝!

흔히 쓰는 매크로라는 녀석.
절차적으로 넣은 명령어를 하나씩 실행해 주는거
해보면 원래 스레드에 덧씌워진다! 중간에 마우스 휙휙 돌리면 거기에 +a됨
델리게이트 이벤트체인에 비해 선녀인 점은 커맨드를 순서대로 실행하는것.
이벤트에서도 그렇기는 하지만 순서가 보장되지는 않는데, 이 경우는 한 번에 간단한 한 가지 커맨드만 하므로
딱히 그런 걱정은 안 해도 되는 것 같다.
받을 때 잘 보면 그냥args[]로 파라미터 받아서 넘겨주고 끝낸다.
단, 주의할 점은 매크로 커맨드에서 직접 원본 커맨드로 가서 .excute()를 해서는 안된다.
반드시 복사해서 실행 해야 되는데, 원본과 결합되면 어떤 문제가 일어날 지 모르기 때문이다.
이거 하고 이거하고 이거 해. → ‘이거’ 는 나중에 물어보지 뭐.
나중에 클라이언트가'이거'가 뭔지 까먹으면?? 망한다.
손님. 이거 가 뭔지 정확히 말씀해 주시면 제가 주문서에 쓰겠습니다.
이거-> 아이스아메리카노 라지사이즈요 → 주문서: ‘아이스아메리카노 라지’.excute() 라고 쓰는것.
큐에다가 커맨드를 박아버리면?
이거 진짜 스레드로 넘겨서 처리할 수 있다. 단순히 큐니까. 큐는 공유자원으로 잡을 수 있으니까.
공용 일감에다가 파바박 넣어놓고 작업을 각각 적당히 빼가서 처리할 수 있는 것이다.
SMT 할때 이렇게 하면? 좋을 것 같은데? 원래 멀티스레딩 할때 CPU0만 개고생하고 작업할당이나 서로 안겹치려고 따지느라
시간 다 잡아먹는데, 이렇게 러프한 작업은 대충 나눠 가져버리면? 대신 완전히 안겹치게 작업단위를 분배해야겠지
단순 순환문같이, 아니면 패킷을 정해진 바이트대로 가져가서 처리하게
로그에 커맨드를 기록했다가 다운시 거기서부터 재실행 해서 복구도 가능하다.
이거 비동기락스텝방식 썼던 언리얼 네트워크 이동시 SavedMovement에 로컬 이동 행동 넣어두고
서버에서 특정 타임스탬프의 정확한 좌표 받으면, 그 타임스탬프, 그 좌표 + 이후 SavedMovement의 행동 적용 썼던거
그대로다.
git이나 다른 형상처리 관련 모시기들, 쿼리를 쓰는 모시기들에서 전부 이런 트랜젝션 단위로 버전 변경을 처리하는데
알고보면 커맨드 하나가 excute() 되면 변경이 일어난 것으로 처리한 것.
쿼리문도 따지고 보면 명령어 셋일 뿐이고 전부 버튼 하나 하나에 매핑된 커맨드일 뿐이라고 생각해도 편하다.
아주 좋잖아?
정리하면 하나의 메소드를 하나의 커맨드로 만들고, 이 때 이름을 좀 예쁘게 잡아주면, 클라는 이름으로 대충 유추해서 그냥 쓰면 되고, 굉장히 일반화 돼 있기 때문에 탬플릿 메소드보다 쓰기가 쉽다.
내가 엔진이니까, 나무 생성 버튼, 돌 생성 버튼, 이런식으로 하나씩 버튼에 넣을 수 있는 커맨드만 주고, 프로그래머는 그냥 버튼의 아이콘이랑 이름만 보고 실행하면 된다.
복잡한 구조가 될 일도 없고, 프로그래머가 혹시 버튼을 잘못 만들었나? 고민할 필요도 없어진다. 그냥 엔진팀에게 이 버튼 안되는데요? 하면 우리는 그 버튼의 리시버만 보면 된다.
아 나무가 업데이트돼서 좌표계가 바뀌었네, 수정하자. 이것만 해주면 되는것.
완전히 캡슐화되고, 클라는 버튼만 누르면 되고, 책임소재도 완전히 분리될 뿐 더러, 모든 함수가 command의 구상 클래스이기 때문에 하나의 명령 큐에 저장이 가능하고
뻗어버리면 체크포인트에서부터 명령큐를 재실행해서 복구도 가능하고, 실행 된 명령을 스택에 넣어서 반대 기능을 실행해 주면 Undo도 쉽게 가능하다.
모든 함수들이 커맨드 하나로 통일되기 때문에 너무너무너무 편해져 버린다.
심지어 클라이언트는 이게 일반 메서드인지, 커맨드로 구현된 메서드인지 알 수도 없고, 알 필요도 없다! 자기가 제대로 실행했다는 사실만 알면 됨.
단점이라고 한다면 체크포인트 찍고 백업을 저장하기 때문에 런타임에 메모리가 좀 많이 들 수 있다는 거?
매개변수로 함수를 커맨드라는 하나의 타입으로 받을 수 있기 때문에, 델리게이트 타입 하나 정의하고 거기에 맞게 람다로 넣거나 인스턴스에다 하나씩 넣어주지 않아도 그냥 그냥 쓸 수 있음. 이게 아주 좋음
아무데서나 그냥 커맨드 상속받아서 슬롯에 할당해 주기만 하면 바로 웨이터 불러다가 주문만 하면 됨!
훨씬 클라이언트에게 친화적인 인터페이스를 제공하는 것. 약간 외국어 능수능란한 웨이터? 델리게이트는 클라이언트가 문법 따져가면서 번역해서 넘겨야 웨이터가 알아듣기 때문
또, 웨이터한테 전달한 요청을 주방장에게(리시버) 넘기지 않고 자기가 처리해 버리는 스마트 커맨드 객체 라는 것도 나온다고 함.
이거 쓰면 또다른장점은 로그 히스토리를 쭉쭉 남길 수 있는 것. 트랜젝션 기반 백업 시스템도 갖출 수 있다. 문제라고 한다면 내용 몰라도 실행 하면 보장되기 때문에. 요청은 요청이지 이게 중요한지 아닌지 모르고 그냥 저장하고 실행하기 때문에
주문폭주 악질 유저의 공격에 취약해 질 수 있다는 것. DNS 공격. 큐에서 비교해서 히스토리 거부하는 추가 기능으로 막거나 하면 된다.
아니면 ssh나 auth 가진 애가 하던가. 매크로이면 중복 몇번 까지만 허용하도록 인증메세지를 다시 전송하던가, 타임아웃을 몇초 돌려준다던가.
어댑터, 퍼사드, 탬플릿메소드, 프록시패턴 나올텐데 비슷한 개념 있으니까 정리.
결국 객체에게 역할을 분리하고, 작은 단위의 위임을 하는데, 얼마만큼? 누구한테? 관리주체는? 목적은? 에 따라서 달라지는 것.
커맨드 패턴의 경우 메서드의 변동성은 별로 없다. 리모콘의 변동성에 초점을 맞춘 것. 있는 버튼들을 조합해서 한 가지 목적을 모두 수행할 수 있을 때만 사용할 것.
예를 들면 키보드 같은것. 각 키는 써져있는대로 버튼 역할만 해줄 뿐, 이외의 신비로운 버튼은 존재하지 않는다. (계산기를 켜서 부정적분을 실행해. 같은 건 있을 필요가 없다.)
그래서 db 접근해서 단순히 읽고, 쓰고, 대체하고, 삽입하고, 예약하고 같은 쿼리문에 쓸 수 있는 것.
약간은 스테이트와 스트레티지에 걸쳐 있다. 리시버를 특정하고, 인터페이스에 있는 기능을 각각의 구상 클래스로 단순 실행만 해줌.
오리->사운드온->”꽥!!” 강아지->사운드온->”멍!!”