views:

452

answers:

7

Hello, 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().

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. If a class has both FeatureX and FeatureY, it can inherit from both, no problem.

My problem is, what if a function/method requires an object that can perform both FeatureX() and 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?

Do I create another interface IFeatureXY that inherits from IFeatureX and IFeatureY? 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.

Is there a simple way to do this? I tried solving the problem using C++ templates and delegation but didn't get too far. 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.

+2  A: 

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.)

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.

Charlie Martin
A: 

If you want ot do it in c++, what about multiple inheritance?

Javier De Pedro
A: 

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.

anon
+2  A: 

If you're not afraid of using templates, you can make your function a template and use SFINAE to check for the two interfaces:

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).

Another possibility is to create an interface IFeatureXY extending both, and use this in the function parameters; 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.

In Java, you could probably do the same thing with bounded type variables (if they allow multiple bounds; I'm not sure now).

jpalecek
Thanks, this is similar to what I had in mind but looks a lot more robust.
Kranar
A: 

WCF has very nice pattern how to determine if some object supports some interface (or class) using 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();
}

This way you can query your object for some inteface. A similar method is used in COM+ in IUnknown::QueryInterface().

Jozef Izso
A: 

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
bb
+1  A: 

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). It lets you bypass some of the wonky issues with doing things like this.

Ron Warholic