【问题标题】:Implementing subclasses with sparse common functionality实现具有稀疏通用功能的子类
【发布时间】:2012-05-01 08:09:25
【问题描述】:

我正在构建一个包含大量类的系统,所有这些类都共享通用功能,但也有少量由重叠的类子集共享的功能。实现这一点的最佳方式是什么?

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

有一个基类SVGElement,它有很多通用的功能。所有其他类(SVGLineSVGCircle...)都直接派生自此。然后,它们具有规范中定义的其他功能(通过 XML 属性),例如:

 - 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 个属性,分布在一个稀疏矩阵中。

【问题讨论】:

  • 给定的设计 => 您不能更改 SVG 规范。但是你能改变类定义/类数吗?
  • 并非如此。设计是<svg:circle> => SVGCircle.javaSVGHasXHasFill.java 等内容的范围很小。对于人类或机器来说,它应该是相当自动化的。
  • 这些类是否真的有任何行为(即它们是否是正确的对象?)或者它们只是映射到 SVG 定义的属性包?
  • 可能他们有很多行为,其中大部分是手工制作的。例如,transform="matrix(...)" 元素可以递归连接以给出整体变换。文本变换的行为不同于几何图元的变换(例如,文本是否旋转?)。化学也是如此 - 例如,我们检查化学键中没有重复的 id。

标签: java subclassing


【解决方案1】:

您可能需要考虑将“通用”功能实现为“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);

【讨论】:

  • 这就是我正在寻找的东西。我没有使用过装饰器模式,这是一个令人信服的理由来做一些阅读!
  • @peter.murray.rust - 您可能听说过著名 GoF 书籍:en.wikipedia.org/wiki/Design_Patterns。我有一个副本,一直在附近,很久没读了:(
  • 我确实听说过 GoF 并且还有其他关于模式的书籍,但我不擅长识别何时使用哪种模式!
猜你喜欢
  • 2011-05-30
  • 1970-01-01
  • 2021-01-28
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 2023-02-12
  • 1970-01-01
  • 2018-01-06
相关资源
最近更新 更多