添加插件支持:要继承的接口还是基类?

发布于 2024-07-13 09:54:17 字数 157 浏览 8 评论 0原文

我正在向我的 .NET 应用程序添加插件支持。 基类对我来说听起来很合理,因此人们可以继承它并覆盖某些调用,也可以保留默认功能或可以使用一些内部辅助函数。

为什么我要选择接口而不是插件基类来继承? 您能告诉我应该选择哪种设计以及为什么吗?

I'm adding plugin support to my .NET application. A base class sounds reasonable to me, so people can inherit it and override certain calls as well can keep the default functionality or can use some internal helper functions.

Why would I choose interface instead of a base plugin class to inherit? Could you tell which design I should choose and why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

暮年慕年 2024-07-20 09:54:17

您应该考虑查看 System.Addin (MAF) 命名空间或托管扩展性框架 (MEF)。 MEF 将是首选,尽管它仍处于预发布阶段,因为它比 MAF 简单得多。 这些选择中的任何一种都可以简化您需要执行的大量管道工作,以便加载加载项并与其交互。

至于在接口和抽象类之间做出选择,如果您选择 MAF 或 MEF,其中一些会为您做好。 在这种情况下最基本的区别是,通过提供抽象基类,您可以为自定义插件(由您或其他开发人员编写)提供继承点,并确保某些方法/属性提供默认行为并强制派生类实现某些所需的方法/属性。 缺点是您仅限于单个基类。

接口绕过了单一基类的限制,仍然为自定义插件提供继承点,并确保实现某些方法/属性,但不能提供任何类型的默认行为。 您也不能在接口中指定除公共成员之外的任何内容,而抽象类可以具有抽象或虚拟非公共成员(通常是受保护的)。

You should consider taking a look at the System.Addin (MAF) namespace or the Managed Extensibility Framework (MEF). MEF would be the preferred choice even though it is still pre-release as it is much simpler than MAF. Either one of those choices simplify a lot of the plumbing work you will need to do in order to get add-ins loaded and interact with them.

As far as making a choice between an interface and an abstract class, if you go with MAF or MEF some of that will be made for you. The most basic differences in this context are that by providing an abstract base class you provide an inheritance point for custom plugins (written either by you or other developers) and ensure that certain methods/properties provide default behavior and force the derived classes to implement certain required methods/properties. The drawback is that you are limited to a single base class.

Interfaces get around the single base class limitation and still provide an inhertiance point for custom plugins and ensure that certain methods/properties are implemented but can't provide any type of default behavior. You also cannot specify anything other than public members in an interface while an abstract class can have abstract or virtual non-public members (typically protected).

一口甜 2024-07-20 09:54:17

使用插件合约的接口。 如果某种类型的插件可能共享某些功能,请创建一个实现该接口的抽象基类。 还要确保您的合同位于实际应用程序之外的程序集中。

请记住,在 .NET 中,没有多重继承。 要求实现者放弃继承槽来为他们提供一些功能并不是一个好主意。

Use an interface for the plugin contract. If a certain type of plugin likely shares certain functionality, make an abstract base class that implements the interface. Also ensure that your contracts are in an assembly outside of your actual application.

Keep in mind that in .NET, you don't have multiple inheritance. Requiring implementers to give up their inheritance slot to provide a little functionality for them is not a good idea.

岁月流歌 2024-07-20 09:54:17

为什么必须是其中之一呢?

您可以将插件必须遵循的契约定义为到处引用的接口。

另外,您还可以定义一个实现该接口的基类,但仅具有为某些您无法提供默认实现的接口函数调用的抽象方法。

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 (); }
}

Why does it have to be one or the other?

You can define the contract that the plugins must follow as an interface which is being referenced everywhere.

Plus, you can also define a base class which implements that interface, but merely has abstract methods that get called for some of the interface functions that you can't provide a default implementation for.

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 (); }
}
浅笑依然 2024-07-20 09:54:17

这里有一篇关于这个主题的好文章:
插件 API 设计

我个人会使用一个接口,并让插件实现所有细节。

There is a good post on this topic here:
Plugin API design

I would personally use an interface, and let the plugins implement all the details.

旧时浪漫 2024-07-20 09:54:17

我认为您应该做的显而易见的事情是让插件为它想要处理的各个事件注册回调(委托)。 这是大多数框架在 .net 中的工作方式

,换句话说,既不是基类也不是接口。 此解决方案的优点是您的插件不必符合任何给定的外部接口或基类,它只需注册其所需的功能即可。

例如,任何给定的 ASP.NET 控件中的“事件”部分都是这样执行的:查看 用户控件

I think the obvious thing you should do is to let the plugin register callback (delegates) for the individual events it wants to handle. This is the way most frameworks work in .net

In other words, neither base classes nor interfaces. The advantage of this solution is that your plugin does not have to conform to any given external interface or base class, it simply registers for the functionality it needs.

As an example, the "Events" sections in any given asp.net control does it this way: Have a look at UserControl

梦言归人 2024-07-20 09:54:17

每个人都忘记提及的是向后兼容性。 您可以在不破坏现有客户端的情况下向基类添加新方法,但无法在不影响现有接口的情况下修改它们。

有一些替代方法可以避免接口的兼容性问题。 例如,当您为应用程序添加新扩展时,您可以创建一个继承旧接口的新接口。 但这有一个缺点,即使用 IClientInterfaceV2 和 IClientInterfaceV3 等类型会使您的体系结构变得臃肿。

我个人的建议是采用类似于 scwagner 建议的方法,并创建一个基类和一个接口。 并向界面用户发出警告,指出未来版本可能会破坏其实现,并且建议使用基类继承策略以避免将来出现兼容性问题。

Something that everyone is forgetting to mention is backwards compatibility. You can add new methods to a base class without breaking existing clients while you cannot modify existing interfaces without affecting them.

There are alternatives to avoid compatibility issues with interfaces. For example, you could create an new interface that inherits from the old one when you include new extensions for your application. But this has the drawback of bloating your architecture with types such as IClientInterfaceV2 and IClientInterfaceV3.

My personal suggestion would be to go with an approach like the one suggested by scwagner and create both a base class and an interface. And include a warning to the interface users stating that future versions might break their implementation and that the base class inheritance strategy is the recommended one to avoid future compatibility issues.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文