1

我的项目中有一个多态结构,并考虑将其重写以使用Visitor Pattern.

基本结构是:我有一些绘图对象(Rectangle, Ellipse, Line,还有更多)当然有一些共同的行为。行为由接口定义Drawable。到目前为止,拖动的行为应该始终相同,但选择的绘制它们应该不同。

因此,我介绍了abstract Figure已经实现的类drag(),但将实现委托drawSelected()给扩展类。

当然,稍后将使用我需要的其他功能扩展该接口,并且还会出现 Figures 的其他实现。

现在我的问题是:您宁愿坚持这种设计,还是切换到Visitor. 如果是这样,为什么?特别是我不确定我目前的方法是否适合在对象本身内部绘制选择的逻辑/算法。

interface Drawable {
    void drag();
    void drawSelected();
}


abstract class Figure implements Drawable {
    protected int x, y, w, h;

    @Override
    void drag() {
        //implementation always the same for different figures
    }
}


class Rectangle extends Figure {
    @Override
    drawSelected() {
        //draw a dashed rectangle around this object
    }
}

class Ellipse extends Figure {
    @Override
    drawSelected() {
        //draw a dashed ellipse around this object
    }
}

class Line extends Figure {
    @Override
    drawSelected() {
        //draw the line itself dashed
    }
}
4

4 回答 4

3

您遇到的问题需要使用不太可能随时间变化的对象结构;可能会添加新的结构(图形),但给定的对象结构(图形)不太可能改变。尽管结构可能不会改变,但您可以在结构上添加越来越多的操作,并且这些操作可能会或可能不会在结构中通用。我认为这些东西为使用该Visitor模式提供了一个用例。

为了进一步详细说明,请考虑添加一个新操作的场景,其中您需要一个实现用于一组图形,另一个实现用于另一组,依此类推。在当前设计中,您可能只能在抽象类中拥有一个通用实现(除非您使用instanceOf,但这又不是一种好的做法),并且必须在每个其他类中覆盖该实现。在使用Visitor模式的情况下,您将始终调用该visit方法(将在运行时绑定),并且您可以在其中决定调用哪个实现。

在当前的设计中,您还可能会遇到一种情况,即在不同的类中有共同的逻辑。但是在Visitor模式中,您可以在访问者类中维护各种实现并在访问方法中重用它们,因此没有代码重复。

Visitor如果需要,模式还可以让您轻松地将给定图形从一种实现切换到另一种实现。

尽管在添加新类时,您需要向访问者界面添加新的实现,但这不会影响您现有的任何类(图形)或其实现。

于 2013-03-16T14:00:02.443 回答
1

查看Visitor来自 GoF 的模式的用法似乎在您的情况下使用该模式是不合适的。

用法

  • 一个对象结构包含许多具有不同接口的对象类,并且您希望对这些对象执行依赖于它们的具体类的操作。
  • 需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免这些操作“污染”它们的类。访问者允许您通过在一个类中定义相关操作来将它们保持在一起。当对象结构被许多应用程序共享时,使用访问者将操作放在那些需要它们的应用程序中。
  • 定义对象结构的类很少更改,但您经常希望在该结构上定义新操作。更改对象结构类需要重新定义所有访问者的接口,这可能代价高昂。如果对象结构类经常更改,那么最好在这些类中定义操作。
于 2013-03-16T13:10:55.010 回答
1

[...] 并且还会出现 Figure 的其他实现

我认为仅出于这个原因,访问者模式不适合您的场景。每当您向层次结构添加新类时,您都必须更改访问者界面及其所有实现。当您的层次结构稳定时,访问者更合适,它允许您轻松添加额外的行为,只需创建新的访问者实现即可。

看看非循环访问者的替代方案。但是仔细考虑使用这些模式,它们会使设计变得比应有的复杂。

于 2013-03-16T13:33:26.980 回答
1

我认为这个问题有点过于宽泛了。我们应该更多地了解您的应用程序架构、功能和要求。我只想为nikpon 的观点添加另一种观点。

考虑最后一点:

定义对象结构的类很少更改,但您经常希望在该结构上定义新操作。更改对象结构类需要重新定义所有访问者的接口,这可能代价高昂。如果对象结构类经常更改,那么最好在这些类中定义操作。

因此,答案取决于您的数字数据实际上是什么以及它们必须执行哪些操作。我会给你一个例子,访客模式可能会更好:

  • 图形只是代表实际图形的数据集合(例如,圆:半径和中心。方形边和中心)
  • 您必须在使用不同 GUI/渲染库的不同系统/架构中绘制图形

在这种情况下,有两个主要后果:

  • 一个图形类可能永远不会改变,或者它的改变可以隐藏在一个永远不会改变的界面后面。(例如,圆始终由中心和半径定义。)
  • 您无法使用单一方法来绘制此对象,因为它会根据使用的图形库而相应更改。如果您将绘图逻辑放入其中drawSelected(),那么对于您使用的每个不同的图形库,您需要修改drawSelected每个类的实现(或使用合适的模式来允许)。

在这种情况下,访客的好处可能是:

  • 您可以跨不同平台和图形库重用 Figure 类,无需任何更改
  • 您可以将绘图操作压缩在每个 [平台|库] 具体的访问者类上。(例如 DrawObjectsOnWindowsVisitor 和 DrawObjectsOnAndroidVisitor)。如果您需要支持不同的平台/库,您可以简单地添加一个访问者,使图形类保持不变。

顺便说一句,情况可能并非如此,最终可以使用其他模式来实现这些目标。

于 2013-03-16T13:42:50.280 回答