我在应用程序中对各种事件进行了一些简单的调度,并使用了这个类层次结构:
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
,但我不喜欢它。
我的问题是你如何设计你的类层次结构以及为什么?这对你来说似乎微不足道,但我没有太多真正的设计经验,我想做得对。
答案 0 :(得分:1)
我认为使用继承的旧设计非常精细,而且不那么复杂。你正在使用多态,就像它应该使用的那样。
我对“更喜欢构图而非继承”的解释(大致)如果你不需要多态行为,那么你应该使用合成而不是继承。
使用ITriggerable方法,您无法解决必须为每个新事件编写子类的问题。您只是使用接口而不是基类。它不是技术继承,但它几乎是一样的。
答案 1 :(得分:0)
我不知道什么对你最好,但好的设计需要提供encapsulation,同时平衡cohesion和coupling的数量。我不会遵循任何有利于构成而不是继承的规则。设计决策有理由。
答案 2 :(得分:0)
你不能用这样的随机名称来判断。子类应遵循“是一个”规则:说Truck
是Vehicle
的子类,然后truck
应该是 vehicle
。< / p>
但是也不要太过于沉溺 - 最重要的是考虑代码重用,而不仅仅是创建一个深层次结构,因为你可以,只创建它,如果它会导致更简单的代码,更好的封装和更多代码重用。
答案 3 :(得分:0)
更喜欢组合而不是继承的建议涉及如何实现重用。组合提供了跨不同类层次结构重用数据和/或行为的能力,以及在运行时替换类型的特定行为的能力。组合不会消除为不同行为创建新类型的需要。
关于调度模型,我过去采用的方法是分离任务,调度,调度监视和调度服务的概念。在我的情况下,我需要安排封装不仅仅是一个固定的时间点,因此它包含指定重复间隔,重复计数等的其他属性。我没有在任务中封装计划,因为任务不是本质上是关注它们何时发生。例如,换油是一项任务,而每3个月是一个可以应用于换油以及其他维护任务的时间表。通过将计划与任务分开,可以为多个任务维护单个监视器,这些任务碰巧共享相同的计划。