2009-12-05 4 views
4

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

В конструкторе для набора классов, все из которого производятся из общего базового класса, он требует ссылки на класс instancing, который должен быть передан. Например,
Foo Foo_i = new (this);

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

С одной стороны, это упрощает TON кода, который моделирует структуру дерева на 5 слоев в аппаратном обеспечении (агенты подключаются к портам на нескольких коммутаторах и т. Д.). С другой стороны, эти объекты довольно тесно связаны друг с другом таким образом, который кажется довольно неправильным, но я недостаточно знаю об OOA & D, чтобы наложить на него свой палец.

Итак, все в порядке? Или это эквивалент OO для инструкции goto?

+0

Я никогда не слышал, что это плохая практика, в некоторых случаях это довольно удобно. – Rob

ответ

2

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

Java, например, использует это много с внутренними классами:

public class Outer { 
    private class Inner { 
    public Inner() { 
     // has access to the members of Outer for the instance that instantiated it 
    } 
    } 
} 
1

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

Другими словами мой контроллер был

class p { 

    private member x 

    private methods 

    private class q { 
    // methods referencing p's private members and methods 
    } 

    x.setListener(new q()); 

} 

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

1

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

Вы не представили конкретный пример, но если класс напоминает вам о goto, это, вероятно, плохая идея.

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

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

2

Похоже, что это может нарушить Law of Demeter, в зависимости от того, сколько Foo нужно знать, чтобы ловить рыбу в классе instancing. Объекты предпочтительно должны быть слабо связаны. Вы бы не хотели, чтобы один класс знал много о структуре другого класса. Один из примеров, который я слышал несколько раз, заключается в том, что вы не передадите свой кошелек клерщику магазина и не будете ловить его внутри.Ваш кошелек - ваш бизнес, и вы найдете то, что вам нужно, чтобы дать клерку и передать его себе. Вы можете реорганизовать свой кошелек, и никто не станет мудрее. Соединение Looser облегчает тестирование. В идеале Foo следует тестировать без необходимости поддерживать сложный контекст.

+0

+1 хорошая аналогия – gtrak

5

Вы стремитесь избегать взаимных ссылок (особенно при использовании сдерживания), но часто их невозможно избежать. То есть родительские отношения с детьми - дети часто должны знать родителя и уведомлять об этом, если происходят некоторые события. Если вам действительно нужно это сделать - выберите интерфейсы (или абстрактные классы в случае C++). Итак, вы создаете класс, который должен реализовать некоторый интерфейс, и инстанцированный класс должен знать его только как интерфейс - это значительно уменьшит сцепление. В некотором отношении такой подход аналогичен вложенному классу слушателя, поскольку он предоставляет только часть класса, но его легче поддерживать. Вот пример C#:

interface IParent 
{ 
    //some methods here 
} 

class Child 
{ 
    // child will know parent (instancing class) as interface only 
    private readonly IParent parent_; 
    public Child(IParent parent) 
    { 
     parent_ = parent; 
    } 
} 

class Parent : IParent 
{ 
    // IParent implementation and other methods here 
} 
Смежные вопросы