简体   繁体   English

C ++ / Java继承与委派与等等

[英]C++/Java Inheritance vs. Delegation vs. etc

I am creating a class library with many different options for possible customizations. 我正在创建一个类库,其中包含许多可能的自定义选项。 For example, you can design your class so that it can perform FeatureX(), or you can design your class so that it can perform FeatureY(). 例如,您可以设计您的类,使其可以执行FeatureX(),或者您可以设计您的类,使其可以执行FeatureY()。

Under normal circumstances, you would simply create an interface IFeatureX with a pure virtual method called FeatureX, and another interface IFeatureY with a pure virtual method called FeatureY. 在正常情况下,您只需使用称为FeatureX的纯虚拟方法创建接口IFeatureX,并使用称为FeatureY的纯虚拟方法创建另一个接口IFeatureY。 If a class has both FeatureX and FeatureY, it can inherit from both, no problem. 如果一个类同时具有FeatureX和FeatureY,则可以同时继承两者。

My problem is, what if a function/method requires an object that can perform both FeatureX() and FeatureY()? 我的问题是,如果一个函数/方法需要一个可以同时执行FeatureX()和FeatureY()的对象怎么办? How do I express a type, in C++ preferably, but an answer in Java could help as well, to ensure that both FeatureX and FeatureY are available? 如何最好用C ++表示类型,但是用Java回答也可以帮助确保FeatureX和FeatureY都可用?

Do I create another interface IFeatureXY that inherits from IFeatureX and IFeatureY? 是否创建另一个继承自IFeatureX和IFeatureY的接口IFeatureXY? Okay... if there are only two features I could get away with this. 好的...如果只有两个功能,我可以解决。 But if there are say... 10 features, the number of possible interfaces becomes massive. 但是,如果说... 10个功能,则可能的接口数量将变得庞大。

Is there a simple way to do this? 有没有简单的方法可以做到这一点? I tried solving the problem using C++ templates and delegation but didn't get too far. 我尝试使用C ++模板和委派来解决问题,但步步未定。 I'm hoping there is a simple solution to this, and there probably is one that I just overlooked. 我希望对此有一个简单的解决方案,也许我只是忽略了一个。

I appreciate any help and advice you guys have. 感谢您提供的任何帮助和建议。

Thanks. 谢谢。

First thing to do is ask if you're trying to do something that can't be expressed simply, and if so, ask yourself if it is really worth doing? 首先要做的是询问您是否正在尝试做一些无法简单表达的事情,如果是,请问问自己是否真的值得做?

Given that you can't find a simpler model of what you want, you're going to need to think about dependencies among the options. 鉴于找不到所需的简单模型,您将需要考虑选项之间的依赖关系。 If you can use Feature X independently of Feature Y, then make them independent interfaces or pure virtual classes (as appropriate to the language.) 如果可以独立于功能Y使用功能X,则使它们成为独立的接口或纯虚拟类(视语言而定)。

If you can't use them independently, make a class that includes both; 如果您不能单独使用它们,请创建一个包含两者的类。 ask yourself why you want FeatureX and FeatureY as separate interfaces, because that pattern of usage suggests they're not independent after all. 问问自己自己为什么要将FeatureX和FeatureY作为单独的接口,因为这种使用模式表明它们毕竟不是独立的。

If you're not afraid of using templates, you can make your function a template and use SFINAE to check for the two interfaces: 如果您不担心使用模板,则可以将函数设为模板,并使用SFINAE检查以下两个接口:

template <class T>
void my_function(const T& data, typename enable_if_c<
    is_convertible<T*, IFeatureX*>::value && 
    is_convertible<T*, IFeatureY*>::value>::type*=0) {
  ...
}

This will create a method for every type that extends both feature interfaces (note that the SFINAE trick is not needed for it to work; an unconstrained template would work, but just fail to compile when you pass a type that doesn't meet the requirements). 这将为扩展了两个功能接口的每种类型创建一个方法(请注意,不需要SFINAE技巧即可起作用;可以使用不受约束的模板,但是当您传递不满足要求的类型时,它将无法编译)。

Another possibility is to create an interface IFeatureXY extending both, and use this in the function parameters; 另一种可能性是创建一个扩展两者的接口IFeatureXY,并在函数参数中使用它。 this has the drawback that types that do implement both interfaces, but not this joint interface would not be usable with this method. 这样做的缺点是, 可以同时实现两个接口但不能实现此联合接口的类型不能用于此方法。

Also, you can pass two arguments to the function, one per interface, and require they are pointers to the same object; 另外,您可以将两个参数传递给函数,每个接口一个,并要求它们是指向同一对象的指针。 this is fragile, but could be hardened by making some template class to hold the two pointers - eg. 这很脆弱,但是可以通过制作一些模板类来容纳两个指针来加强它-例如。 product_type<IFeatureX*, IFeatureY*> , which would be initialized by the single object in question and which would hold the two types. product_type<IFeatureX*, IFeatureY*> ,它将由所讨论的单个对象初始化,并且将包含两种类型。

In Java, you could probably do the same thing with bounded type variables (if they allow multiple bounds; I'm not sure now). 在Java中,您可能会对有界类型变量做同样的事情(如果它们允许多个界限;我现在不确定)。

Although there are ways to add completely disparate features, you might want to think about the scope of these added features. 尽管有多种方法可以添加完全不同的功能,但是您可能需要考虑这些添加功能的范围。 Are they going to be related to your main class library? 它们将与您的主类库相关吗? (One could argue that if they aren't they shouldn't be part of it) (一个人可能会争辩说,如果不是,那么就不应成为其中的一部分)

If they have enough in common to warrant adding features you can look for something like the decorator pattern ( http://en.wikipedia.org/wiki/Decorator_pattern ). 如果它们有足够的共同点来保证添加功能,则可以寻找诸如装饰器模式( http://en.wikipedia.org/wiki/Decorator_pattern )之类的东西。 It lets you bypass some of the wonky issues with doing things like this. 通过这种方式,您可以绕开一些棘手的问题。

如果您想用C ++做到这一点,那么多重继承又如何呢?

Possibly you are being too fine grained. 可能您的粒度太细了。 Consider a numeric class - you can perform multiplication, division, addition, subtraction, etc. However, you would not create separate interfaces for each of these operations - you would create one interface called SupportsArithmetic (or whatever) that covered them all. 考虑一个数字类-您可以执行乘法,除法,加法,减法等。但是,您不会为这些操作中的每一个创建单独的接口-您将创建一个称为SupportsArithmetic的接口(或涵盖所有内容)。

WCF has very nice pattern how to determine if some object supports some interface (or class) using IExtensionCollection<T>.Find<E>() . WCF具有非常好的模式,该模式如何使用IExtensionCollection<T>.Find<E>()确定某些对象是否支持某些接口(或类IExtensionCollection<T>.Find<E>() IExtensionCollection . IExtensionCollection

IFeatureX feature = argument.Find<IFeatureX>();

if (feature != null)
{
    // Find() returned an instance so there is an implementation
    // of IFeatureX available

   feature.FeatureX();
}

This way you can query your object for some inteface. 这样,您可以查询对象的某些接口。 A similar method is used in COM+ in IUnknown::QueryInterface() . IUnknown :: QueryInterface()中的COM +中使用了类似的方法。

Why you need interfaces? 为什么需要接口? Use templates: 使用模板:

template< typename T >
void some_function( const T& t )
{
    // use featureX functions
    t.fetatureX();

    // use featureY functions
    t.featureY();
}

Usage: 用法:

SomeClass x; // object with only X feature
some_function( x ); // compile time error, because featureY() doesn't exists

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

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