向一组类添加行为

时间:2010-04-06 10:49:11

标签: c# java design-patterns

我定义了一个Event类:

Event

并且所有以下类都继承自Event:

SportEventType1 SportEventType2 SportEventType3 SportEventType4

现在我只会参加SportEvents但是我不知道将来我是否会想要其他一些与体育没有任何关系的活动。

稍后,我将想要绘制一些带有从事件中获取的信息的图形,并且绘图逻辑可能有点复杂。但是,目前,我认为我不应该想到绘图将如何完成,我相信如果绘图部分不是作为Event / SportEventX类链的一个组成部分,那也许会更好。 / p>

我正在寻找这个问题的解决方案。我知道我可以让Event有一个实例变量(属性,对于java crowds)指向某个IDrawInterface,但这会使Event类“假设”它将在以后用于绘图。如果可能的话,我想让Event类忘记这一点。

谢谢!

3 个答案:

答案 0 :(得分:3)

您打算在Event类层次结构之外保持绘图过程的知识是好的。

在OO语言中处理此类事物的常用方法是Visitor Pattern

如果您无法实际更改Event类以添加访问者所需的accept(Visitor v),则可以考虑使用DecoratorAdapter。尽管如此,让accept方法因子类而异,可能会让人感到痛苦。我会考虑更多这一点,也许今晚可以补充说明。现在,我必须开始工作。

答案 1 :(得分:1)

另一个解决方案可能是拥有一个DrawbleEvent抽象类,其中不同的sportchevents可以继承。

public abstract DrawableEvent
{
    Event event;
    IDrawingStrategy drawingstrategy;
    public Draw()
    {   
        drawingStrategy.Draw();
    }

}
public SportingEvent1 : DrawableEvent
{
    SprortingEvent1(Event event, IdrawingStrategy strategy)
    {
         this.event=event;
         this.drawingstrategy = strategy;
    }
}

事件参考可以根据需要的位置转到策略或sprorting事件。

答案 2 :(得分:1)

这是一种更复杂但非常灵活的方法。我们将定义一个接口 对于可以绘制某些事件的类型:

interface IEventRenderer
{
    // Draw the given event, if it can. Return true if the event was drawn,
    // false otherwise.
    bool Draw(Event event);
}

它做了两件事:它检查是否可以绘制给定事件,如果是, 吸引它。否则它会失败并返回false。

例如,可以渲染Sport1Events的类看起来像:

class Sport1EventRenderer : IEventRenderer
{
    public bool Draw(Event event)
    {
        var sportEvent = event as Sport1Event;

        // can only draw this type
        if (sportEvent == null) return false;

        // draw the event...

        return true;
    }
}

然后我们将定义一个注册表类。它的工作是保持一个集合 这些渲染器并将事件交给适当的工作 之一:

class EventRendererRegistry
{
    public void Add(IEventRenderer renderer)
    {
        mRenderers.Add(renderer);
    }

    public void Draw(Event event)
    {
        foreach (var renderer in mRenderers)
        {
            if (renderer.Draw(event)) break;
        }
    }

    private readonly List<IEventRenderer> mRenderers = new List<IEventRenderer>();
}

它所做的只是找到可以成功绘制事件的第一个渲染器。 然后你会使用它:

var registry = new EventRendererRegistry();
registry.Add(new Sport1EventRenderer());

registry.Draw(someEvent);

<强>优点:

  • 事件类型未与任何呈现代码耦合。
  • 渲染器彼此没有耦合。
  • 渲染器仅与他们关心的事件相关联。 (例如a Sport2EventRenderer不需要与Sport1Event耦合。)
  • 渲染可以执行任意逻辑来确定它们是否合适。我们只是 在这里做一个类型测试,但我们可以看到事件是否实现了某个 界面,具有一定的属性,处于某种状态等。
  • 相对较快。没有超越简单铸造的反思。

<强>缺点:

  • 相当复杂。
  • 在运行时可能无法找到匹配的渲染器。
  • 每次都必须遍历渲染器集合才能找到匹配项。