Подтвердить что ты не робот

Плохо ли практика ООП иметь объекты, ссылающиеся друг на друга?

Простите мою пустоту. Я делаю игру, в которой несколько персонажей имеют отношения друг с другом, и они должны иметь возможность взаимодействовать друг с другом и хранить некоторые данные о взаимоотношениях относительно того, как они относятся друг к другу.

У меня есть объект для каждого символа. Разве плохо для каждого из этих объектов персонажей иметь массив всех других объектов символа для выполнения этих взаимодействий? Есть ли лучший способ сделать это?

РЕДАКТИРОВАТЬ ответы на вопросы: Мой язык - С#.

То, что я думал, это то, что класс установки создавал массив всех символов, а затем передавал этот массив в качестве параметра конструктору каждого символа.

Что касается типов отношений, то существует пять символов, но я хотел бы сделать его расширяемым, если в дальнейшем будет добавлено больше. У персонажей есть разговоры друг с другом. На то, что они говорят, влияет их настроение и то, как они относятся к персонажу. Кроме того, что говорит другой персонаж, они влияют на их настроение и то, как они относятся к персонажу. У них могут быть разговоры "один на один" или говорить в группах, поэтому персонаж "А" может сразу что-то сказать персонажам B, C, D, E и F.

Кстати, я так многому увлекаюсь из этой темы. Большое вам спасибо, всем!

4b9b3361

Ответ 1

Неплохо для того, чтобы объекты сохраняли ссылки друг на друга - для узлов в древовидном графике нередко сохраняются ссылки на их дочерние узлы, а для дочерних узлов - ссылки на их родительский node.

Одна вещь, которая может стать проблемой, - это то, что вы описываете, поскольку каждый символ хранит ссылки на все остальные символы. Это NxN-матрица и взорвет ваше использование памяти по мере увеличения количества символов.

Альтернативой сохранению списка всех объектов символа в каждом объекте-символом может быть создание ассоциативного списка или словаря, в котором ключ (символ 1, символ 2), а контент - это отношения. Этот список может быть глобальным и хранить все отношения между всеми символами. Преимуществом здесь является то, что он растет линейно с количеством фактических отношений, а не экспоненциально с количеством символов в системе.

Ответ 2

Как правило, полезно избегать ненужных ссылок между объектами, но определение того, что не нужно, очень субъективно и зависит от проблемы.

Если каждый символ имеет уникальный идентификатор (например, уникальное имя), вы можете просто сохранить для каждого символа коллекцию идентификаторов символов и "чувство" об этом символе. Используя другой тип CharacterManager, вы можете найти символ на основе идентификатора.

Другой вариант (может быть предпочтительным, если мнения являются лишь одним из незначительных аспектов игры) состоит в том, чтобы иметь отдельный класс "RelationshipManager", который может отвечать на запросы, такие как "Как chararacter X воспринимает символ Y"? Это может быть лучшим дизайном, поскольку эта ответственность управляется отдельно от вашего основного характера. Этот менеджер может напрямую ссылаться на символы или использовать идентификаторы.

Ответ 3

Нет, это совсем не плохая практика. Очевидно, вы могли бы сделать это таким образом, чтобы было трудно поддерживать или понимать, но нет ничего неправильного в ссылках между объектами.

Хотя я бы рекомендовал любой тип коллекции, который предоставляет ваш язык, а не массив, нет ничего плохого в том, что вы предлагаете.

Ответ 4

Если отношение длительное, это имеет смысл сделать это. Я не знаю, как работает ваша игра, но маловероятно, что все персонажи могут взаимодействовать друг с другом в любой момент времени. В более временных ситуациях вам может понадобиться какой-то "визит", где лидер игры передает ссылки на встречающиеся стороны.

Вы также можете выявить разные уровни деталей с помощью интерфейсов: если Ghoul встречает волшебника, он может просто получить ссылку на человека для Мастера, поскольку Ghoul не рассматривает разные типы людей по-разному. Используя эту "необходимость знать базу", вы уменьшаете количество связей в коде, и вы можете использовать код лучше: вам не нужно писать какой-либо новый код, если Ghoul посещает фермера.

Ответ 5

У меня есть объект для каждого символа. Это плохо для каждого из этих персонажей объектов, чтобы иметь массив всех другие объекты персонажа для выполнять эти взаимодействия? Есть ли лучший способ сделать это?

Это действительно зависит от взаимодействия между персонажами, которые делятся на две категории:

1) Действия - Мутирует некоторое состояние на B

В этом случае вы, вероятно, напишете что-то вроде:

class Player {
    Player[] players;

    ...

    public void ExchangeItem(Item item, string playerName) {
        Player target = players.First(x => x.Name = playerName);
        target.Items.Add(item);
        this.Items.Remove(item);
    }
}

2) Реакции - B слушает изменение состояния в A

Вы не будете писать:

public class Player {
    Player[] players;

    public void Die() {
        foreach(Player p in players)
            p.Mourn();
    }
}

Его о единой ответственности. Объекты должны знать и заботиться о своем собственном состоянии и поведении, они не должны знать о других. В этом случае метод Die, похоже, слишком много знает о том, как справляются с ним другие игроки.

Вместо этого вы можете переписать его как событие:

class Player {
    public event EventHandler PlayerDied;

    public void Die() {
        if (PlayerDied != null)
            PlayerDied(this, EventArgs.Empty);
    }
}

Другие объекты могут подключаться к событию PlayerDied и реагировать так, как они хотят.

Ответ 6

В дизайне OO общий подход к такой проблеме - шаблон посредника

Проблема с описанным вами подходом заключается в том, как обновить отношения? Например, если символ A удаляется из игры, как обновляются другие символы, чтобы удалить символ A из их отношений?

Я бы предложил другой объект, который управляет отношениями. Затем этот объект может отвечать за обновление отношений. Используя тот же пример, когда символ A удален, диспетчер связей просто удаляет все отношения, связанные с этим символом.

Ответ 7

Я заметил, что с объектно-ориентированным дизайном, если это звучит логично для кого-то, кто не кодирует, то вы, вероятно, хороши.

Скажите, что у вас есть такси... такси должно знать, в какой компании оно работает правильно?

Или ребенок должен знать, кто его родитель прав?

Очевидно, держите его в разумных пределах.

Ответ 8

Один подход, когда у вас есть дюжина различных объектов, которые все ссылаются друг на друга, заключается в том, чтобы помещать что-то посредине - посредника, который содержит все ссылки. Каждый затем ссылается на других персонажей через посредника. Вы уменьшаете количество ссылок от n ^ 2 до 2n - каждый знает посредника, и он знает всех.

Ответ 9

Один из вариантов, который вы могли бы изучить, - это идея центра сообщений. У вас есть центральный объект, задачей которого является отправка сообщений другим объектам. Другие объекты выражают свою заинтересованность в получении сообщений путем регистрации с объектом уведомления. Преимущество такого подхода состоит в том, что вы отделяете объекты друг от друга, а также избегаете проблем с памятью, связанных с циклическим удержанием ссылки. Одним из недостатков может быть узкое место в объекте уведомления, если вы отправляете тонну сообщений.

Ответ 10

Не обязательно, но это зависит от того, как вы определяете и ссылаетесь на отношения. Например, что произойдет, если вы хотите заменить один объект символа на другой? Вам нужно будет обновить все объекты, которые ссылаются на этот объект?

Ответ 11

Проблема, которую вы описали, может быть естественным образом смоделирована как график, где узлы - ваши игровые персонажи, а отношения между ними - это ребра графа. Ребра могут быть направлены или неориентированы в зависимости от характера отношений между вашими игровыми персонажами. Вы можете использовать графическую базу данных, такую ​​как Neo4j, если она подходит вашей проблеме.

Что касается хранения ссылок, я думаю, что важно помнить, что принцип проектирования имеет, насколько это возможно, конструкцию в ваших конструкциях.

Ответ 12

У меня есть объект для каждого символа. Это плохо для каждого из этих персонажей объектов, чтобы иметь массив всех другие объекты персонажа для выполнять эти взаимодействия? Есть ли лучший способ сделать это?

Интерфейс в одном слове является ответчиком для этого. Кроме того, вы в конечном итоге будете беспорядочно обновлять все ссылки в определенный момент времени.