В последнее время я боролся с некоторой повторяющейся проблемой проектирования, которую я не знаю, как элегантно решить.
Скажем, я делаю игру с парой игроков, и для каждого игрока есть несколько связанных фигур. Вместе эти части образуют полусложную коллекцию или структуру. Теперь я мог реализовать эту структуру двумя способами: либо неявно хранить структуру с помощью указателей в самих частях, то есть:
class BigPiece extends Piece {
Piece opposingPiece, nextPiece, previousPiece, index;
}
Или я мог бы реализовать эту структуру в классе коллекции и сохранить информацию централизованной:
class SomeCollection<Collection<Piece>> {
SomeOtherCollection<Collection<Piece>> collection
= new SomeOtherCollection<Collection<Piece>>();
public SomeCollection() {
collection.add(new PieceCollection<Piece>();
collection.add(new PieceCollection<Piece>();
collection.add(new PieceCollection<Piece>();
}
public Piece getPiece(int playerIndex, int pieceIndex) {
collection.get(playerIndex).get(pieceIndex);
}
public Piece getOpposingPiece(int playerIndex, int pieceIndex) {
int nextPlayerIndex = collection.listIterator(playerIndex).nextIndex();
return this.collection.get(nextPlayerIndex).get(pieceIndex);
}
}
Теперь я обычно отдаю предпочтение второму, но оно основано только на моих силах, и у меня не так много опыта в дизайне классов, особенно в больших приложениях. Я вижу плюсы и минусы с обеих сторон.
Проблема, с которой я обычно сталкиваюсь при первом решении, заключается в том, что вам все равно нужно создавать ассоциации в каком-либо сборщике или фабрике, которые фактически связывают объекты вместе. Это не кажется мне надежным. Кто может заверить меня, что все указатели на самом деле верны в течение всего срока службы приложения?
Второе решение централизует данные больше. Это действительно ослабляет более высокие классы (такие как отдельные части). Проблема, с которой я обычно сталкиваюсь, заключается в том, что всякий раз, когда я хочу просмотреть эту коллекцию, я должен сделать это на более низком уровне. Вы не можете спросить фигуру «Эй, какая у вас фигура противника?». Нет, вам нужно получить игровой объект, чтобы получить указатель на вашу коллекцию, который вы затем спросите, что является противоборствующим элементом. Это делает больше «управляемых» классов, которые собирают данные со всего вашего приложения (метод chaining = () для окончательной реализации вашего алгоритма. Это, кажется, нарушает Закон Деметры .
Конечно, я мог бы добавить указатель на соответствующую коллекцию для каждого отдельного предмета, но я не знаю, хорошая ли это идея, поскольку это только дублирующая информация.