1

我正在创建一个具有许多不同选项的类库以进行可能的自定义。例如,您可以设计您的类以便它可以执行 FeatureX(),或者您可以设计您的类以便它可以执行 FeatureY()。

在正常情况下,您只需创建一个接口 IFeatureX 和一个名为 FeatureX 的纯虚方法,以及另一个接口 IFeatureY 和一个称为 FeatureY 的纯虚方法。如果一个类同时具有 FeatureX 和 FeatureY,它可以从两者继承,没问题。

我的问题是,如果一个函数/方法需要一个可以同时执行 FeatureX() 和 FeatureY() 的对象怎么办?我如何表达一个类型,最好用 C++,但 Java 的答案也可以帮助确保 FeatureX 和 FeatureY 都可用?

我是否要创建另一个从 IFeatureX 和 IFeatureY 继承的接口 IFeatureXY?好的...如果只有两个功能,我可以摆脱这个。但是如果有说... 10 个功能,可能的接口数量就会变得庞大。

有没有一种简单的方法可以做到这一点?我尝试使用 C++ 模板和委托来解决问题,但并没有走得太远。我希望有一个简单的解决方案,并且可能有一个我只是忽略了。

我感谢你们的任何帮助和建议。

谢谢。

4

7 回答 7

2

首先要做的是问问你是否想做一些不能简单表达的事情,如果是的话,问问自己这是否真的值得做?

鉴于您无法找到所需的更简单模型,您将需要考虑选项之间的依赖关系。如果您可以独立于 Feature Y 使用 Feature X,那么让它们成为独立的接口或纯虚拟类(视语言而定)。

如果您不能独立使用它们,请创建一个包含两者的类;问问自己为什么要将 FeatureX 和 FeatureY 作为单独的接口,因为这种使用模式表明它们毕竟不是独立的。

于 2009-04-07T21:01:17.797 回答
2

如果您不怕使用模板,可以将您的函数设为模板并使用 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) {
  ...
}

这将为扩展两个功能接口的每种类型创建一个方法(请注意,它不需要 SFINAE 技巧即可工作;不受约束的模板可以工作,但是当您传递不符合要求的类型时会编译失败)。

另一种可能性是创建一个接口 IFeatureXY 扩展两者,并在函数参数中使用它;这有一个缺点,即确实实现了两个接口的类型,但不是这个联合接口的类型不能用于此方法。

此外,您可以将两个参数传递给函数,每个接口一个,并要求它们是指向同一对象的指针;这是脆弱的,但可以通过制作一些模板类来保存两个指针来加强 - 例如。product_type<IFeatureX*, IFeatureY*>,它将由所讨论的单个对象初始化,并且将包含两种类型。

在 Java 中,您可能可以对有界类型变量做同样的事情(如果它们允许多个边界;我现在不确定)。

于 2009-04-07T21:32:06.333 回答
1

尽管有一些方法可以添加完全不同的功能,但您可能需要考虑这些添加的功能的范围。它们会与您的主类库相关吗?(有人可能会争辩说,如果他们不是,他们不应该成为其中的一部分)

如果它们有足够的共同点来保证添加功能,您可以寻找装饰器模式(http://en.wikipedia.org/wiki/Decorator_pattern)之类的东西。它可以让你绕过一些做这样的事情的不稳定问题。

于 2009-04-07T21:44:37.643 回答
0

如果你想在 C++ 中做,那么多重继承呢?

于 2009-04-07T21:04:38.817 回答
0

可能你的粒度太细了。考虑一个数字类 - 您可以执行乘法、除法、加法、减法等。但是,您不会为这些操作中的每一个创建单独的接口 - 您将创建一个名为 SupportsArithmetic (或其他)的接口,涵盖所有这些操作。

于 2009-04-07T21:05:52.730 回答
0

WCF 有一个非常好的模式,如何使用IExtensionCollection<T>.Find<E>(). IExtensionCollection

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

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

   feature.FeatureX();
}

通过这种方式,您可以查询您的对象以获取某些接口。在 COM+ 中的IUnknown::QueryInterface()中使用了类似的方法。

于 2009-04-07T21:38:39.080 回答
0

为什么需要接口?使用模板:

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

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

用法:

SomeClass x; // object with only X feature
some_function( x ); // compile time error, because featureY() doesn't exists
于 2009-04-07T21:44:17.817 回答