实现具有稀疏公共功能的子类

时间:2012-05-01 08:09:26

标签: java subclassing

我正在构建一个具有大量类的系统,所有类都具有共同的功能,但是由于重叠的类子集共享了较少的功能。实现这个的最佳方式是什么?

作为一个例子,我将采用SVG(我正在实施化学的子集),尽管我在其他领域有例如化学。这个以及相关的问题在XML Schema中有明确的,不可改变的设计规范。

有一个基类SVGElement,它有很多共同的功能。所有其他类(SVGLineSVGCircle ...)都直接来自此。然后,他们在规范中定义了其他功能(通过XMLattributes),例如:

 - x
 - width
 - fill
 - opacity

还有更多。请注意,设计是给定的 - 我们无法重新创建新元素或属性。例如,SVG同时包含circleellipse(经典问题),其中一个使用r(adius),另一个使用widthheight。子类共享通用功能时,可以使用通用代码。

似乎有以下解决方案:

  • 实现每个子类中的每个函数。 (容易出错且繁琐)
  • 实现超类(SVGElement)中的所有函数,并使派生方法无操作。 (对于开发人员来说,这是一种臃肿,难以理解和令人沮丧的)
  • 创建接口(hasWidth)并为每个(WidthImplementor)创建一个委托子类。然后每个类都有一个接口列表(每个SVG属性可能最多20个),可能有100-200个这样的实现者。
  • 从架构中自动生成代码。我试过这个并且它的工作很笨拙,但我还没有很好的实现。它也不易维护(注意大多数XML-to-Java系统不适合构建库系统,所以我必须自己做很多事情)

也许是其他人。

我知道还有其他关于如何设计抽象的SO问题,但这里很大程度上是固定的。我想要一个通用的解决方案,而不仅仅是一个SVG(它被用作一个可以理解的例子)。例如,化学标记语言(CML)还具有100-200个子类和100-200个属性,以稀疏矩阵进行扩展。

1 个答案:

答案 0 :(得分:2)

您可能需要考虑将“常用”功能实施为“Decorators”。然后,您可以在解析SVG元素时在运行时应用这些装饰器。

abstract class SVGElement {

    public void draw (void) {
        return;
    }

    public boolean hasWidth (void) {
        return false;
    }

    public boolean hasHeight (void) {
        return false;
    }

    // ..
}

// An abstract decorator
abstract class SVGElementDecorator extends SVGElement {

    protected SVGElement decoratedElement;

    public SVGElementDecorator (SVGElement decoratedElement) {
        this.decoratedElement = decoratedElement;
    }

    public void draw (void) {
        decoratedElement.draw ();
    }
}

// Decorator to add width functionality
class WidthDecorator extends SVGElementDecorator {

    private double width;

    public WidthAndHeightDecorator (SVGElement decoratedElement) {
        super(decoratedElement);
    }

    // override base class implementation
    public boolean hasWidth (void) {
        return true;
    }

    // implement a new method
    public double getWidth (void) {
        return width;
    }

    public void draw (void) {

        // do special stuff for width
        // ..

        // then draw the rest
        decoratedElement.draw ();
    }
}

然后,当你看到一个椭圆:

SVGElement ellipse = new SVGElement();
ellipse = new WidthDecorator (ellipse);
ellipse = new HeightDecorator (ellipse);