Наследование от связанных классов - PullRequest
1 голос
/ 02 июня 2011

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

class Container {
  Element[] elements;
}
class Element {
  // ... data...
  Container holds_me;
}

Конструктор Container создает объект Element, чтобы обернуть каждый содержащийся объект, и устанавливает свои указатели holds_me на себя.

Теперь я хочу наследовать от этих классов. Мне нужен класс DerivedContainer, который наследуется от Container и содержит DerivedElement объекты, где DerivedElement наследуется от Element и ссылается на содержащий DerivedContainer объект. Как правильно это сделать (или это неправильно)?

Самым простым для конструктора DerivedContainer является создание DerivedElement s, сохранение их в elements и установка указателя holds_me на себя. Тогда все методы Container и Element будут работать, но любые новые методы, определенные в DerivedContainer и DerivedElement, должны будут понижать объекты, содержащиеся в elements и holds_me, чтобы вызывать любые новые методы. на них, которые не были определены в базовых классах. Это не выглядит красиво; так что мне интересно, есть ли лучшее решение?

Ответы [ 3 ]

1 голос
/ 02 июня 2011

Если ваш язык поддерживает это, вы можете использовать шаблоны / шаблоны. Класс Container может иметь класс Elements в качестве параметризованного типа. Таким образом, вы можете забыть о потуплении стихий.

1 голос
/ 02 июня 2011

Да, это правильный способ сделать это, без какой-либо дополнительной информации, ИМХО. Это имеет смысл, если вы считаете, что все методы в Element могут применяться к каждому элементу, но классы only , которые должны знать что-либо о производном наборе функциональных возможностей, являются (в идеале только) DerivedElement и (при необходимости) DerivedContainer. Другими словами, для всех остальных элементы и контейнеры являются только элементами и контейнерами.

Иногда вы можете сделать немного лучше с шаблонами (C ++) или дженериками (Java), поскольку мысль об этих функциях заключается в том, что Container<Element> знает, что он содержит Elements, а Container<DerivedElement> знает, что он содержит DerivedElements, но если у вас гетерогенный Контейнер, вам действительно нужно, чтобы каждый подкласс обрабатывал производную функциональность, пытаясь снизить значение.

0 голосов
/ 13 февраля 2012

В случае, если кому-то интересно, я понял, что можно сделать более или менее то, что я изначально хотел, используя абстрактные типы. Вот некоторый код Scala:

abstract class Container { ctnr =>
  type E <: Element
  class Element { this : E =>
    // data
    def holds_me = ctnr
  }
  var elements : Array[E]
}

Исходный контейнер - это абстрактный класс, содержащий как вложенный класс элементов, так и абстрактный тип элементов. Утверждение подтипа E <: Element требует, чтобы E всегда было подклассом Element, в то время как самоссылка this : E => заставляет любое создание экземпляра Element принадлежать типу E (как определено некоторой реализацией Container).

class ContainerImpl extends Container {
  type E = Element
  // initialize 'elements' using 'new Element()'
}

abstract class DerivedContainer extends Container {
  override type E <: DerivedElement
  class DerivedElement extends Element { this : E =>
    // more data
  }
}

class DerivedContainerImpl extends DerivedContainer {
  type E = DerivedElement
  // initialize 'elements' using 'new DerivedElement()'
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...