访客模式还是多态?

时间:2013-03-16 12:49:20

标签: java oop design-patterns visitor-pattern

我的项目中有一个多态结构,并考虑重写它以使用Visitor Pattern是否有价值。

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

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

当然接口稍后会扩展我需要的其他功能,并且还会有附加的图形实现。

现在我的问题是:你宁愿坚持这个设计,还是转而使用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 个答案:

答案 0 :(得分:2)

您遇到的问题需要使用不太可能随时间变化的对象结构;可能会有新的结构(图)可能会被添加,但给定的对象结构(图)不太可能改变。虽然结构可能不会改变,但您可以在结构上添加越来越多的操作,这些操作在结构中可能相同也可能不常见。我认为这些事情成为使用Visitor模式的用例。

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

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

如果需要,

Visitor模式还可以让您轻松地将给定数字从一个实现切换到另一个实现。

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

答案 1 :(得分:1)

查看来自GoF的Visitor模式的用法似乎在您的案例中使用该模式是不合适的。

使用实例

  
      
  • 对象结构包含许多具有不同接口的对象类,并且您希望对这些对象执行操作   取决于他们的具体课程。
  •   
  • 需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免“污染”   他们的课程与这些操作。访客可让您保持相关   通过在一个类中定义它们来共同操作。当对象   结构由许多应用程序共享,使用Visitor来放   仅在那些需要它们的应用程序中进行操作。
  •   
  • 定义对象结构的类很少改变,但是您经常希望在结构上定义新的操作。改变了   对象结构类需要将接口重新定义为all   访客,这可能是昂贵的。如果是对象结构类   经常改变,然后定义操作可能更好   那些课程。
  •   

答案 2 :(得分:1)

  

[...]以及图的其他实现将会出现

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

请查看acyclic visitor以获取替代方案。但是要认真思考使用这些模式,它们会使设计变得更加复杂。

答案 3 :(得分:1)

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

考虑最后一点:

  

定义对象结构的类很少改变,但是经常这样   想要在结构上定义新的操作。改变对象   结构类需要重新定义所有访问者的界面,   这可能是昂贵的。如果对象结构类发生了变化   通常情况下,最好定义那些操作   类。

所以答案取决于你的数据实际是什么以及他们必须执行哪些操作。 我将举例说明访客模式可能更好:

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

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

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

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

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

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