Это - плохо практика ООП, чтобы иметь ссылку объектов друг друга? [закрытый]

25
задан lala 12 May 2010 в 18:45
поделиться

12 ответов

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

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

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

19
ответ дан 28 November 2019 в 20:49
поделиться

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

2
ответ дан 28 November 2019 в 20:49
поделиться

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

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

1) Действия - A изменяет какое-то состояние на 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 и реагировать так, как они хотят.

3
ответ дан 28 November 2019 в 20:49
поделиться

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

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

0
ответ дан 28 November 2019 в 20:49
поделиться

В ОО-проектировании распространенным подходом к решению подобной проблемы является паттерн Посредник

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

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

7
ответ дан 28 November 2019 в 20:49
поделиться

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

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

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

9
ответ дан 28 November 2019 в 20:49
поделиться

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

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

3
ответ дан 28 November 2019 в 20:49
поделиться

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

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

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

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

2
ответ дан 28 November 2019 в 20:49
поделиться

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

Одним словом, интерфейс - ответ на этот вопрос. В противном случае вы попадете в беспорядок, обновляя все ссылки в определенный момент времени.

-3
ответ дан 28 November 2019 в 20:49
поделиться

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

1
ответ дан 28 November 2019 в 20:49
поделиться

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

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

4
ответ дан 28 November 2019 в 20:49
поделиться

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

0
ответ дан 28 November 2019 в 20:49
поделиться