Передача ссылок на объект без необходимости через посредника - PullRequest
2 голосов
/ 30 августа 2009

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

Кто-нибудь знает, где провести эту линию?

Или хороший способ решить проблему распределения ссылок среди зависимых объектов?

Ответы [ 5 ]

3 голосов
/ 30 августа 2009

Используйте Закон Деметры (с умеренностью и хорошим вкусом, а не догматически). Если вы кодируете a.b.c.d.e, что-то не так - вы навсегда пригвоздили реализацию a, чтобы иметь b с c, который ... EEP! -) Один или самое большее две точки - это максимум, который вы должны использовать. Но альтернатива НЕ состоит в том, чтобы превращать вещи в глобальные переменные (и гарантировать, что потокобезопасный, глючный, трудно поддерживаемый код!), А в том, чтобы каждый объект «покрывал» те характеристики, которые он предназначен поддерживать, как часть его интерфейса для клиенты идут вперед, вместо того, чтобы просто позволить бедным клиентам проходить через такие бесконечные цепочки вложенных ссылок!

1 голос
/ 30 августа 2009

Я полагаю, что ваш вопрос раскрывает что-то в ваших классах Может быть, обязанности можно улучшить? Может быть, перемещение какого-либо кода решит проблемы?


Скажи, не спрашивай.

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

Класс A хочет выполнить расчет и запрашивает данные B. Иногда целесообразно, чтобы A велел B выполнить работу, возможно, передавая некоторые параметры. Это могло бы заменить «getName ()» B, используемое A для проверки правильности имени, методом «isValid ()» на B. «Запрашивающий» был заменен «говорящим» (вызывая метод, который выполняет вычисления).

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


Переместить данные вокруг

В других случаях я перемещаю некоторые данные. Например, если поле перемещает два объекта вверх, длина «цепочки получателей» уменьшается на два.

Я полагаю, что сначала никто не может найти правильную модель. Сначала я думаю об этом (использование рукописных диаграмм быстро и очень помогает), затем кодирую его, затем снова думаю о реальной вещи ... Затем я кодирую остальное, и любые запахи, которые я чувствую в коде, я думаю снова ...


Разделение и объединение объектов

Если для метода A нужны данные из C, а B - посредник, я могу попробовать, если A и C будут иметь что-то общее. Возможно, A или часть A могут стать C (возможное расщепление A, слияние A и C) ...


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

1 голос
/ 30 августа 2009

В некоторых случаях глобальный не так уж и плох.

Учтите, вы, вероятно, программируете с использованием API операционной системы. Там полно глобалов, вы, вероятно, можете получить доступ к файлу или реестру и написать в консоль. Посмотрите на ручку окна. Вы можете делать множество вещей, чтобы получить доступ к состоянию, которое является глобальным для всего компьютера или даже через Интернет ... и вам не нужно передавать одну ссылку на ваш класс, чтобы получить к нему доступ. Все эти вещи являются глобальными, если вы получаете доступ к API операционной системы.

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

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

Хм, во всяком случае. Я не совсем уверен, какой совет я пытаюсь дать здесь, кроме как сказать, что структурирование кода - это всего лишь баланс! И то, как это сделать для вашей конкретной проблемы, зависит от ваших предпочтений, предпочтений людей, которые будут использовать код, как вы чувствуете себя в день на академическом или прагматическом уровне, насколько велика база кода, насколько критична безопасность Система и как далеко от срока завершения.

1 голос
/ 30 августа 2009

Это пахнет абстракцией, которая может нуждаться в некотором улучшении. Вы, кажется, нарушаете Закон Деметры.

0 голосов
/ 30 августа 2009

У меня есть три шаблона для этого:

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

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

  3. Поместите все различные вещи, которые передаются как ссылки, в один класс, а затем передайте только этот один экземпляр класса как единственную вещь, которая передается. Например, для отображения DOM требуется много свойств (например, графический дескриптор GDI, координаты области просмотра, события обратного вызова и т. Д.) ... Я поместил все эти вещи в один экземпляр Context, который передается как единственный параметр для методов визуализируемых узлов DOM, и каждый метод может получить любые свойства, которые ему нужны, из этого параметра контекста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...