我的应用程序的正确设计 - 继承正确的选择?

时间:2009-10-15 09:37:17

标签: inheritance oop

我在应用程序中对各种事件进行了一些简单的调度,并使用了这个类层次结构:


abstract class ScheduledEvent
{
    public DateTime When{ get; set; }

    public abstract void Trigger();
}

class WhateverEvent : ScheduledEvent
{
  public override void Trigger();
}

class AnotherEvent : ScheduledEvent
{
  public override void Trigger();
}

class Scheduler
{
  public AddEvent(ScheduledEvent event)
}

我的应用程序工作正常,但我不喜欢这个设计,因为每当我想添加一个新事件时,我必须在层次结构中添加一个新的后代,并且所有书籍都说更喜欢组合而不是继承所以我试过这种方法:


interface ITriggerable
{
    void Trigger();
}

class WhateverEvent : ITriggerable
{
  public void Trigger();
}

abstract class ScheduledEvent
{
    private ITriggerable triggerable;
    public ScheduledEvent(ITriggerable t) { 
        triggerable = t; 
    }
    public DateTime When{ get; set; }

    public void Trigger() { triggerable.Trigger(); }
}

但问题立刻发生了。对于每种类型的事件,都有一个用于编辑其属性的表单,如下所示:


class WhateverForm : Form
{
    WhateveverForm(WhateverEvent ev) { ... }
}

此表单包含WhateverEvent的所有属性以及When的属性ScheduledEvent。使用我的新层次结构,此属性不再可用。我当然可以将ScheduledEvent的引用添加到WhateverEvent,但我不喜欢它。

我的问题是你如何设计你的类层次结构以及为什么?这对你来说似乎微不足道,但我没有太多真正的设计经验,我想做得对。

4 个答案:

答案 0 :(得分:1)

我认为使用继承的旧设计非常精细,而且不那么复杂。你正在使用多态,就像它应该使用的那样。

我对“更喜欢构图而非继承”的解释(大致)如果你不需要多态行为,那么你应该使用合成而不是继承。

使用ITriggerable方法,您无法解决必须为每个新事件编写子类的问题。您只是使用接口而不是基类。它不是技术继承,但它几乎是一样的。

答案 1 :(得分:0)

我不知道什么对你最好,但好的设计需要提供encapsulation,同时平衡cohesioncoupling的数量。我不会遵循任何有利于构成而不是继承的规则。设计决策有理由。

答案 2 :(得分:0)

你不能用这样的随机名称来判断。子类应遵循“是一个”规则:说TruckVehicle的子类,然后truck应该 vehicle。< / p>

但是也不要太过于沉溺 - 最重要的是考虑代码重用,而不仅仅是创建一个深层次结构,因为你可以,只创建它,如果它会导致更简单的代码,更好的封装和更多代码重用。

答案 3 :(得分:0)

更喜欢组合而不是继承的建议涉及如何实现重用。组合提供了跨不同类层次结构重用数据和/或行为的能力,以及在运行时替换类型的特定行为的能力。组合不会消除为不同行为创建新类型的需要。

关于调度模型,我过去采用的方法是分离任务,调度,调度监视和调度服务的概念。在我的情况下,我需要安排封装不仅仅是一个固定的时间点,因此它包含指定重复间隔,重复计数等的其他属性。我没有在任务中封装计划,因为任务不是本质上是关注它们何时发生。例如,换油是一项任务,而每3个月是一个可以应用于换油以及其他维护任务的时间表。通过将计划与任务分开,可以为多个任务维护单个监视器,这些任务碰巧共享相同的计划。