게임 항목에 대한 클래스 계층 구조에 대한 조언
문제
나는 진흙 엔진을 쓰고 있으며 방금 게임 객체 모델을 시작했는데, 이는 확장 가능해야합니다.
내가 한 일이 지저분 해져서 주로 도움이 필요하지만 더 잘 작동하는 다른 솔루션을 생각할 수는 없습니다.
나는 전화 수업이 있습니다 MudObject
, 그리고 다른 수업은 전화를 걸었습니다 Container
, 컨테이너에는 여러 가지를 포함 할 수 있습니다 MudObjects
, 그러나 a MudObject
그러나 그 자체 MudObject
S가 포함되어 있는지 알아야합니다.
그래서 그들은 다음과 같이 보입니다.
public abstract class MudObject
{
Container containedBy;
}
public abstract class Container : MudObject
{
List<MudObject> Contains;
}
(이는 예제이며 일부 예선 및 액세스 수정 자, 속성 등이 누락됩니다).
이제 이것 자체가 지저분 해 보이지만 믹스에 다른 것을 추가하겠습니다.
Item
a MudObject
모든 시각적 품목 (예 : 무기)은 상속되지만, 이들 중 일부는 컨테이너 (가슴과 같은)이어야합니다. 그러나 C#의 여러 상속과 같은 것은 없으므로 인터페이스로 내려 오는 것이 가장 좋은 선택은 컨테이너를 인터페이스로 만드는 것입니다 (내가 볼 수있는 한). 그게 추가되는 것입니다 MudObject
컨테이너로 컨테이너가 업데이트됩니다. MudObject
에스 .containedBy
값.
이 일을하게하는 아이디어, 아니면 물건을 너무 복잡하게 만드는 함정에 빠지고 있습니까?
그렇다면 무엇을 제안 할 수 있습니까?
해결책
당신이 요구하는 것은 합리적이며 복합 디자인 패턴
다른 팁
나는 당신이 과도하게 복잡하고 있다고 생각합니다. mudobjects가 다른 mudobjects를 포함 할 수 있다면, 당신이 필요한 단일 기본 클래스는 다음을 따라야합니다.
public abstract class MudObject
{
MudObject containedBy; //technically Parent
List<MudObject> Contains; //children
}
이것은 WinForms 및 ASP.NET의 작동 방식과 유사합니다. 많은 컨테이너 컨트롤은 모두 컨트롤이며 하위 제어 모음을 포함 할 수 있습니다.
당신이 원하는 것은 상당히 합리적입니다. 그것은 다른 컨트롤의 컨테이너가 될 수있는 Windows 양식 컨트롤과 다르지 않습니다.
당신이해야 할 일은 자신의 구현을 만드는 것입니다. List<MudObject>
:
public class MudObjectList : List<MudObject>
무엇보다도 기능 추가를 구현하는 것 :
public void new Add(MudObject obj)
{
obj.ContainedBy = this;
base.Add(obj);
}
참고 :이 메소드 그림자는 재정의 대신에 이전 추가 기능을 추가합니다.
이런 식으로 추가시 포함시 포함 된 속성을 즉시 채 웁니다. 물론 당신의 뒷면은 null
, 그것은 그것이 최상위 객체임을 의미합니다.
마지막으로, 나는 분리 할 필요가 없다고 생각합니다 MudObject
그리고 Container
컨테이너가되기 때문에 수업은 MudObject
(FF는 C# 3.0 자동 속성을 사용합니다) :
public abstract class MudObject
{
MudObject ContainedBy { get; set; }
MudObjectList Contains { get; set; }
}
모든 mudobjects 용기를 만들지 않겠습니까? ... 또는 적어도 클래스 코드 측면에서 다른 개체를 포함 할 수 있습니다. 예를 들어
public abstract class MudObject
{
MudObject containedBy;
List<MudObject> contains;
}
그런 다음 객체 자체에 일종의 플래그를 설정하여 플레이어가 물체의 유형을 사용하여 파악하기보다는 실제로 물건을 객체 자체에 넣을 수 있는지 확인할 수 있습니다.
사실, 그것은 둘 다 항목이라는 것이 나쁜 생각입니다. 그리고 컨테이너. 이것은 ILIST에 대한 가정을 만드는 여러 바인딩 시나리오를 깨뜨립니다. 그래서 가슴의 경우, 나는 품목 재산을 가지고 싶어 할 것입니다 ~에 가슴은 컬렉션이지만 가슴을 가슴으로 보냅니다.
그러나 질문에 따라 질문에 대해 ...
나는 mudobject를 인터페이스로 만들고 싶은 유혹을받을 것입니다 ... 그런 식으로, 당신은 다음과 같은 것을 사용할 수 있습니다. 이것은 자동 육아와 함께 콘크리트 물체의 일반적인 용기를 제공합니다.
public interface IMudObject
{
IMudObject Container { get; set; }
/* etc */
}
public class MudContainer<T> : Collection<T>, IMudObject
where T : IMudObject
{
public IMudObject Container { get; set; }
protected override void ClearItems()
{
foreach (T item in this)
{
RemoveAsContainer(item);
}
base.ClearItems();
}
protected override void InsertItem(int index, T item)
{
SetAsContainer(item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
RemoveAsContainer(this[index]);
base.RemoveItem(index);
}
protected override void SetItem(int index, T item)
{
RemoveAsContainer(this[index]);
SetAsContainer(item);
base.SetItem(index, item);
}
void RemoveAsContainer(T item)
{
if (item != null && ReferenceEquals(item.Container, this))
{
item.Container = null;
}
}
void SetAsContainer(T item)
{
if (item.Container != null)
{
throw new InvalidOperationException("Already owned!");
}
item.Container = this;
}
}
상속 대답에 대한 구성이라는 아이디어를 가지고 사라진 것 같습니다.
아마도 나는 이런 일을 더 할 수있을 것입니다
public class Container<T> where T : MudObject
{
List<T> Contains;
MudObject containerOwner;
public Container(MudObject owner)
{
containerOwner = owner;
}
// Other methods to handle parent association
}
public interface IMudContainer<T> where T : MudObject
{
Container<T> Contains { get; }
}
public class MudObjectThatContainsStuff : IMudContainer
{
public MudObjectThatContainsStuff()
{
Contains = new Container<MudObject>(this);
}
public Contains { get; }
}
Marc의 답변에 따라 후드 아래에서 양방향 부모-자식 관계를 유지하는 몇 가지 클래스를 작성하십시오.