2011-06-01 80 views
1

这个问题是关于任何静态类型语言的OOP。假设我有两个类,它们的实例维护着彼此的指针/引用。在我的情况下,一个类是一个容器,另一个类是一个包含对象的包装器,它包含一个指向它所在容器的指针。从链接类继承

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

Container构造器创建一个对象Element给每条包含的对象,并设置其holds_me指针本身。

现在我想从这些类继承。我想要一个DerivedContainer类,它从Container继承和包含DerivedElement对象,其中从ElementDerivedElement继承,是指含DerivedContainer对象。什么是正确的方式来做到这一点(或者是错误的做法)?

最简单的事情是为DerivedContainer的构造函数来创建DerivedElement S和它们存储在elements及其holds_me指针设置为自身。随后的ContainerElement所有的方法都可以工作,但在DerivedContainerDerivedElement定义的任何新的方法将不得不垂头丧气,以调用未在基类定义它们的任何新方法elementsholds_me举行的对象。这看起来不太漂亮;所以我想知道,有没有更好的解决方案?

+0

只是一个建议 - 您使用双链接的连接可能最终成为问题。如果你的容器类有一个静态查找方法“findContaienrWith(object)”,它可能会减少你稍后会遇到的一些复杂性。此外,该方法可以在您添加需求时重新实现(例如,您需要两个容器容纳相同对象或类似令人讨厌的情况)。 – 2011-06-01 21:48:21

回答

1

是的,这是做的,没有任何的更多信息,恕我直言,以正确的方式。这是有道理的,如果你认为所有的元素的方法可以应用到每一个元素,但只应该知道的派生的功能集(理想情况下只)DerivedElement和(如有必要)DerivedContainer什么。换句话说,对其他人来说,元素和容器只有元素和容器。

有时您可以使用模板(C++)或泛型(Java)做一些更好的工作,因为这些功能背后的想法是,Container<Element>知道它存放元素,而Container<DerivedElement>知道它拥有DerivedElements,但是如果您拥有一个异构的Container,你必须让每个子类通过尝试向下转换来处理派生的功能。

+0

好的,谢谢。我希望派生类可以以某种方式确保它们的引用仅指向其他派生类。 – 2011-06-01 22:22:16

1

如果您的语言支持,您可以使用泛型/模板。 Container类可以将Elements类作为参数化类型。这样,你可以忘记向下转换元素。

+0

但是'Container '不会是'Container '的子类,是吗? – 2011-06-01 22:16:54

+0

是的,但这真的有必要吗?凭借原始设计,无论内容如何,​​Container都是一个容器。它所包含的元素可以构成一个类的层次结构,但是对于泛型设计来说,这仍然是正确的。我不明白为什么要将Container 作为Container 的子类。是因为Liskov原理吗? (容器必须是Container ,因此它必须是子类) – 2011-06-02 13:45:07

+0

从我的示例中可能不太清楚。我并不打算让Container成为一个通用的容器对象;在我预期的应用程序中,它更具体一些_happens_还包含一堆元素,DerivedContainer以不同于包含不同类型元素的方式扩展Container的功能。 – 2011-06-03 04:07:49

0

如果有人有兴趣,我已经意识到,它可能做更多或更少什么,我本来想在这里使用抽象类。下面是一些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()' 
}