我正在给我的.NET应用程序添加插件支持。对我来说,一个基类听起来很合理,这样人们就可以继承它并覆盖某些调用,同时也可以保留默认功能或使用一些内部帮助函数。
为什么我会选择接口而不是基插件类来继承?你能告诉我应该选择哪种设计以及为什么吗?
为什么我会选择接口而不是基插件类来继承?你能告诉我应该选择哪种设计以及为什么吗?
使用接口来定义插件的契约。如果某种类型的插件可能共享某些功能,请制作一个实现该接口的抽象基类。同时确保您的合同位于实际应用程序之外的程序集中。
请记住,在.NET中,您不能进行多重继承。强制实现者放弃他们的继承位置为他们提供一点功能并不是一个好主意。
为什么要选择一个而不是另一个呢?
您可以将插件必须遵循的契约定义为接口,并在各处引用它。
此外,您还可以定义一个基类来实现该接口,但仅具有调用某些接口函数的抽象方法,因为您无法为其中一些接口函数提供默认实现。
public interface IPlugin
{
void Initialize ();
void Stuff ();
}
public class PluginBase : IPlugin
{
protected abstract DoInitialize ();
protected abstract DoStuff ();
void IPlugin.Initialize { this.DoInitialize (); }
void IPlugin.Stuff { this.DoStuff (); }
}
我认为你应该做的显而易见的事情就是让插件为它想要处理的个别事件注册回调(委托)。这是大多数 .net 框架工作的方式。
换句话说,既没有基类也没有接口。这种解决方案的优点是,插件不必遵守任何给定的外部接口或基类,它只需注册所需的功能即可。
例如,任何给定 asp.net 控件中的“事件”部分都是这样做的:看看 UserControl。
每个人都忽略了向后兼容性这一点。您可以向基类添加新方法而不会破坏现有客户端,但是您不能修改现有接口而不影响它们。
有避免接口兼容性问题的替代方案。例如,当您包括新的应用程序扩展时,可以创建一个从旧接口继承的新接口。但是这样做会使您的体系结构膨胀,并产生像 IClientInterfaceV2 和 IClientInterfaceV3 这样的类型。
我个人的建议是采用像 scwagner 建议的方法,同时创建基类和接口,并向接口用户发出警告,指出未来版本可能会破坏其实现,并且基类继承策略是避免未来兼容性问题的推荐策略。