简体   繁体   English

使用类(而不是接口)来设置插件机制是否不正确?

[英]Is it incorrect to use classes (instead of interfaces) to set up plug-in mechanism?

Assume this hypothetical situation: I have a hierarchy of classes: 假设这种假设情况:我有一个类的层次结构:

public class MyBase : System.Windows.Forms.TreeNode 
{ 
    public virtual void Init() {...} 
}

Now I want to allow third parties to use MyBase to develop their derived classes like these: 现在,我希望允许第三方使用MyBase来开发其派生类,如下所示:

public class Drv1 : MyBase { public override void Init() {...} }
public class Drv2 : MyBase { public override void Init() {...} }

I want my application be able to use Drv1 and Drv2 as plug-ins. 我希望我的应用程序能够使用Drv1和Drv2作为插件。

Now, my questions are: 现在,我的问题是:

  1. Is it incorrect (or bad practice) to use classes (instead of interfaces) to set up plug-in mechanism? 使用类(而不是接口)来建立插件机制是不正确的(或不好的做法)?

  2. Did I make a mistake I didn't use interfaces to provide THIRD-PARTIES with an interface ? 难道我犯了一个错误,我没有使用接口来提供第三缔约方接口 (because I want to persuade others to develop plug-ins for my app) (因为我想说服其他人为我的应用开发插件)

  3. If answer of question 2 is YES, how could I use interfaces (because MyBase is derived from TreeNode) ? 如果问题2的答案是“是”,那么我该如何使用接口(因为MyBase是从TreeNode派生的)? (this answer is critical for me) (这个答案对我很关键)

Many thanks in advance. 提前谢谢了。

Im using following rules: 我使用以下规则:

If there is any code required in base then go for class . 如果base中需要任何代码,请class


If you need only structure or you need to "inherit" more than one class , use interfaces . 如果只需要结构,或者需要“继承”多个class ,请使用interfaces


If you need both, features and multiple inheritance use both. 如果同时需要,则功能和多重继承都需要使用。


Its really depends what you do with that classes later on. 这实际上取决于您稍后对这些类的处理方式。

In your case you should be using base class as virtual method has some code in it, and you inherit from class that is 3rd party for you. 在您的情况下,您应该使用基class因为virtual方法中包含一些代码,并且您从属于第三方的类继承。

But once your business classes should use different implementation of that class then its worth of adding interfaces and use it in IoC or something. 但是一旦您的业务类应该使用该类的不同实现,那么它值得添加接口并在IoC或其他方面使用它。

I think going for Interfaces for only sake of it is not correct approach. 我认为仅出于它的目的而去接口是不正确的方法。

Is it incorrect (or bad practice) to use classes (instead of interfaces) to set up plug-in mechanism? 使用类(而不是接口)来建立插件机制是不正确的(或不好的做法)?

Neither C# or .NET has anything that labels this as incorrect. C#或.NET都没有将其标记为错误的内容。 They describe under what circumstances your code will continue to work, and when it won't. 它们描述了您的代码在什么情况下可以继续工作,什么时候不起作用。 Bad practice is a matter of opinion, but there are advantages and disadvantages to both approaches. 不好的做法是一种见解,但是两种方法都有其优点和缺点。

If answer of question 2 is YES, how could I use interfaces (because MyBase is derived from TreeNode) ? 如果问题2的答案是“是”,那么我该如何使用接口(因为MyBase是从TreeNode派生的)? (this answer is critical for me) (这个答案对我很关键)

If your callers need to provide a type that is derived from TreeNode , and you wish to use an interface, then you can. 如果您的调用者需要提供派生自TreeNode的类型,并且您希望使用接口,则可以。

public interface IMyInterface {
    void Init() {...}
}

You cannot require classes implementing IMyInterface to derive from TreeNode , but you do not need to: you can ensure that the only way this gets exposed to your own application is via a generic registration method, where the generic type constraints do force the type to both derive from TreeNode and implement this interface: 您可以不需要实现IMyInterface类从TreeNode派生,但是您不需要:您可以确保将其公开给您自己的应用程序的唯一方法是通过通用注册方法,其中通用类型约束确实将类型强制为两种从TreeNode派生并实现此接口:

public void RegisterTreeNode<T>() where T : TreeNode, IMyInterface {...}

If plugins are able to call RegisterTreeNode<Drv1>() , you're assured at compile time that it's going to match your requirements. 如果插件能够调用RegisterTreeNode<Drv1>() ,则可以确保在编译时它将满足您的要求。 You may of course use a different method signature, possibly one that deals with individual instances of the TreeNode class, it's the type constraints that are key here. 您当然可以使用不同的方法签名,可能是处理TreeNode类的各个实例的方法签名,这是类型约束在这里很关键。 If a caller attempts 如果来电者尝试

class X : IMyInterface { public void Init() {...} }

and then 接着

RegisterTreeNode<X>();

the compiler will simply reject this. 编译器只会拒绝此操作。 The plugin may create instances of this X itself, but if your application never sees them, they cannot cause any harm. 该插件可能会创建此X本身的实例,但是如果您的应用程序从未看到过它们,则它们不会造成任何伤害。

Then third parties can do: 然后第三方可以执行以下操作:

public class Drv1 : TreeNode, IMyInterface { ... }
public class Drv2 : TreeNode, IMyInterface { ... }

or even 甚至

public class Drv3 : SuperTreeNode, IMyInterface { ... }

where SuperTreeNode is derived from the standard TreeNode . 其中SuperTreeNode是从标准TreeNode派生的。

This is probably the main benefit of using an interface here: it's compatible with existing classes which provide additional functionality on top of the standard TreeNode . 这可能是在此处使用接口的主要好处:它与现有类兼容,这些类在标准TreeNode之上提供了附加功能。

This cuts both ways: the main benefit of using a common base class here, rather than an interface, would be that your own code can provide additional functionality. 这有两种方式:在这里使用通用基类而不是接口的主要好处是您自己的代码可以提供其他功能。

PS: Depending on what you're after, it may also be possible to decouple this, to make your base class / interface responsible for creating TreeNode objects, rather than deriving from TreeNode . PS:根据您要执行的操作,也可以将其解耦,以使您的基类/接口负责创建 TreeNode对象,而不是从TreeNode派生。 The general rule that favours this approach is called "composition over inheritance", and worth reading up on. 支持这种方法的一般规则称为“组成而不是继承”,值得一读。 It may or may not be a good fit for your particular use case. 它可能适合您的特定用例,也可能不合适。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM