Фон
Вот настоящая проблема, над которой я работаю: я хочу представить карты в карточной игре Magic: The Gathering . Большинство карт в игре выглядят нормально, но некоторые из них разделены на две части, каждая со своим именем. Каждая половина этих двухкомпонентных карт рассматривается как сама карта. Поэтому для ясности я буду использовать Card
только для обозначения чего-то, что является либо обычной картой, либо половиной карты, состоящей из двух частей (другими словами, чем-то, имеющим только одно имя).
Итак, у нас есть базовый тип, карта. Цель этих объектов на самом деле просто держать свойства карты. Они на самом деле ничего не делают сами.
interface Card {
String name();
String text();
// etc
}
Есть два подкласса Card
, которые я называю PartialCard
(половина карты из двух частей) и WholeCard
(обычная карта). PartialCard
имеет два дополнительных метода: PartialCard otherPart()
и boolean isFirstPart()
.
Представители
Если у меня есть колода, она должна состоять из WholeCard
s, а не Card
s, поскольку a Card
может быть a PartialCard
, и это не имеет смысла. Поэтому я хочу, чтобы объект представлял «физическую карту», то есть что-то, что может представлять один WholeCard
или два PartialCard
элемента s. Я предварительно вызываю этот тип Representative
, и у Card
меня будет метод getRepresentative()
. A Representative
почти не предоставит прямой информации о картах, которые он представляет, он только укажет на нее / них. Теперь моя блестящая / сумасшедшая / глупая идея (вы решаете), что WholeCard наследует от обоих Card
и Representative
. В конце концов, это карты, которые представляют себя! WholeCards может реализовать getRepresentative
как return this;
.
Что касается PartialCards
, они не представляют себя, но у них есть внешнее Representative
, которое не является Card
, но предоставляет методы для доступа к двум PartialCard
s.
Я думаю, что эта иерархия типов имеет смысл, но она сложная. Если мы рассматриваем Card
s как «концептуальные карты», а Representative
s как «физические карты», то большинство карт оба! Я думаю, вы могли бы поспорить, что физические карты на самом деле содержат концептуальные карты, и что это не одно и то же , но я бы сказал, что это так.
Необходимость литья типов
Поскольку PartialCard
s и WholeCards
есть оба Card
s, и обычно нет веских причин для их разделения, я бы обычно просто работал с ними Collection<Card>
. Поэтому иногда мне нужно приводить PartialCard
s, чтобы получить доступ к их дополнительным методам. Прямо сейчас я использую систему, описанную здесь, потому что я действительно не люблю явные приведения. И, как Card
, Representative
будет необходимо привести либо к WholeCard
или Composite
, чтобы получить доступ к фактическим Card
s, которые они представляют.
Так что просто для резюме:
- Базовый тип
Representative
- Базовый тип
Card
- Тип
WholeCard extends Card, Representative
(доступ не требуется, он представляет себя) - Тип
PartialCard extends Card
(дает доступ к другой части) - Тип
Composite extends Representative
(дает доступ к обеим частям)
Это безумие? Я думаю, что это действительно имеет большой смысл, но я, честно говоря, не уверен.