클린코드니 솔리드원칙이니 꼭 지켜야 하는건 아니라고 알고있지만
지키려는 시늉을 안하면 스파게티를 볶아버려서 질문하러 왔습니다.
예시 설명)
인터페이스를 상속받아 만들어진 [ 곰, 용, 호랑이 ] 변신상태가 있음. (enter, update, exit 활용하는 상태패턴 )
[베이스 컨트롤러 A (모노비헤이비어) ] 를 상속받는 B,C,D 스크립트가 있으며 이는 각각 [ 곰, 용, 호랑이 ] 상태 전용 컨트롤러 스크립트임.
기존에는 베이스 컨트롤러 A만 플레이어 오브젝트에 붙여넣고
상태에 따라 A스크립트에 "곰, 용, 호랑이 전용 함수를 다 우겨넣어서" 상태패턴에서 그냥 가져와 쓰면 구현은 가능했습니다.
(ATTACK_BEAR, ATTACK_DRAGON 등)
공용함수인 '기본움직임', '공격', '방어' 등을 가상화 혹은 추상화하여 코드중복을 피하고
곰, 용, 호랑이 스크립트에서 전용 함수로 오버라이드해서 사용하려고 했는데
상태패턴 스크립트는 인터페이스 상속이라 베이스 컨트롤러 A를 상속받는것도 아니고, 베이스 컨트롤러 A의 함수를 재정의 할 수도 없어서 b,c,d를 추가했습니다.
"구현하고 싶은 것"은 결국 상태패턴에 따라
B,C,D 중 하나의 컨트롤러 스크립트만 사용하고 싶습니다. (스크립트 A는 오브젝트에 붙인 상태로)
그런데 위 사진처럼 상속받는 B,C,D 스크립트를 만들어서 3개를 한꺼번에 오브젝트에 붙이고 선택적으로 쓰자니
b,c,d 스크립트의 start, update 등 함수가 한번에 돌아갈거같고
A만 오브젝트에 붙이고 B,C,D의 start, update 함수 등은 OptionalStart(), OptionalUpdate()로 만든 후, b,c,d 객체를 생성한 다음
A 스크립트의 Update() 안에서 c.OptionalStart(); c.OptionalUpdate(); 이런식으로 처리하는것도 정상적인 접근방식이 아닌거같아서 질문드려요.
이런 구조일때 어떻게 만들어야 할까요? 알고 계시는 구조나
공부해야 할 검색 키워드라도 알려주시면 공부해보겠습니다.
한꺼번에 붙여놓고 상태에 따라 enable=false또는 true로 활성화 하나만 시켜서 하면 안되나요? enable이 false면 Start랑 Update안돌아가지 않나요..?갑자기 저도 헷갈리네요..
상태패턴 관리하듯이 다 붙이고 컴포넌트를 enable로 관리하는게 나을까요 답변감사합니다
저라면 그렇게 했을거 같아요 저도 지식이 깊진 않아서 합리적이냐 하면 그건 잘 모름.. 다른 고수분들이 추가적으로 설명 달아주실듯..
의견감사합니다 고려해보겠습니다
지금 구조면 BCD가 A를 상속받을게 아니라 그냥 별로의 클래스인데 인터페이스만 구현하도록 하고 BCD를 전부 A가 가지고있든 말든 상관없지만 현재 활성화된 모듈만 별도의 변수에 담아서 그놈의 함수들을 호출하도록 하면 될듯
A의 가상함수들을 빼고 인터페이스 X를 만들어서 B,C,D가 상속받게 하고 B,C,D는 해당 함수 재정의 후 A에서 함수호출만 하라는 말씀이신가요?
인터페이스는 구현하는거지 상속받는건 아니긴 하다만.. 뭐 그런말이긴 하지.. 내가 답이라는건 아니고 그냥 구조적으로 A를 상속받는 BCD를 A가 가지고있는 모양새가 이상하다는 거였음
b,c,d 의 부모를 붙이는것도 이상하긴 했는데 바꿔야겠네요 감사합니다
흠 내 수제비를 보여주고 싶군
내 수제비가 제일 못생겼는데
스테이트만있고 스테이트머신이 없는거아님?
보통 update안은 a.OptionalUpdate(); c.OptionalUpdate(); 이런식이아니고 스테이트머신에서 currentState.Update() 식으로돌림. 한번에 한 상태만 돌아가게.
아니면 걍 코드 일부를 올려봐여. 깃헙이면 더 좋고
A 내부에서 currentState.Update()를 돌리는데 스테이트 머신의 Update(PlayerController player)에서는 b,c,d의 함수를 쓰지 못해서 문제였어요 그래서 PlayerController(a스크립트)에서 b,c,d 스크립트를 객체 생성 후 player.b.Attack(); or player.c.Attack(); 이렇게 구현해야하나? 가 질문이었습니다 너무 대충 질문해서 혼동이 있네요 안돌아가는 코드여도 일단 만들어보고 나중에 다시 올려보겠습니다 답변 감사합니다
첨에 했던 방식이 맞는거같음. 플레이어는 하나의 State 를 인터페이스로 들고있고, 그 인터페이스에따라 attack든 뭐든 하는거지. 근데 거기서 문제가 bcd가 a의 기능이나 함수를 못쓰는게 문제라면, 그 필요한 a의 기능이나 함수도 bcd의 공통 상속 혹은 또다른 인터페이스로 묶어버리면 그만이지 않을까싶음
A는 결국 IState 를 들고있고, bcd는 각각 IState를 상속받은 별개의 인터페이스. 그리고 공통으로 사용되어야할 함수나 기능은 IState에 다 넣고, 그걸 bcd에서 확장 혹은 재정의해서 사용하거나 하면 되지 않을까 그럼 A라는 스크립트 하나만 가지고있는채로 될거같은데
답변 읽어보니 구조적으로 A가 부몬데 A를 붙이고 자식 B,C,D 함수 쓰는게 이상하긴 하네요 A 동작구현을 인터페이스로 옮기고 그걸 상속받은 B,C,D를 따로쓰는게 맞는거같아요 감사합니다
모노비헤비어문제도 걍 IState에 Start만들어서 A의 Start에서 istate.start 하면 그만인거같고 오버라이드는 어차피 bcd에서 하면됴ㅣ고
인터페이스로 묶는게 ㄷ맞는거같네요 답변 감사합니다
디자인패턴으로 치면 전략패턴을 사용했는데 나라면 상태 패턴으로 접근했을듯. 변신후 해당 객채가 완전히 별개의 객채가 아닌 상태인데 컨트롤러도 상태로 바야 하지 않을까?
이상한 고민을 하는것 같은데B,C,D 에 Start 랑 Update 함수가 다 사용된다고 문제될거는 없지오히려 사용이 안되면 문제인거임 Start는 당연 BCD각각 클래스에 필요한 데이터를 초기화하고, 상위 클래스인 A의 START를 호출해서A에서 요구하는 공통된 변수들도 초기화해야하는거고UPDATE 같은경우는 당연히 A에서 공통적으로 수행하는 부분은 상위 클래스의 함수를 호출해서 수행해주고B,C,D에서 색다르게 요구하는 부분들은 B,C,D의 UPDATE 함수부분에 추가로 기입해서 처리해줘야지
하위 클래스의 함수는 public override string ToString() // 이런식으로 override 넣어주고 상위 클래스 함수 호출할떄는 base.ToString(); 이런식으로 필요한 부분에 넣어서 수행해줘 오버라이딩 하면 기본적으로 상위클래스의 update, start가 필요하니까 뭐? 하위클래스에서 상위클래스의 update, start가 수행되면 안된다고? 그럼 애초에 상속을 받으면 안되는거였제~~
patial라고, 한번 찾아봐 그게, 같은이름으로 여러개 정의할수있어서 쓸만함