Question

Je suis en train de créer une bibliothèque de classe avec de nombreuses options différentes pour les personnalisations possibles. Par exemple, vous pouvez concevoir votre classe afin qu'il puisse effectuer FeatureX (), ou vous pouvez concevoir votre classe afin qu'il puisse effectuer FeatureY ().

Dans des circonstances normales, vous pouvez tout simplement créer une interface IFeatureX avec une méthode virtuelle pure appelée FeatureX, et un autre IFeatureY d'interface avec une méthode virtuelle pure appelée FeatureY. Si une classe est à la fois FeatureX et FeatureY, il peut hériter à la fois, pas de problème.

Mon problème est, si une fonction / méthode requiert un objet qui peut effectuer à la fois FeatureX () et FeatureY ()? Comment puis-je exprimer un type, en C ++ de préférence, mais une réponse en Java pourrait aider aussi, à faire en sorte que les deux FeatureX et FeatureY sont disponibles?

Dois-je créer une autre IFeatureXY d'interface qui hérite de IFeatureX et IFeatureY? D'accord ... s'il n'y a que deux caractéristiques que je pouvais sortir avec cela. Mais s'il y a dire ... 10 caractéristiques, le nombre d'interfaces possibles devient massif.

Y at-il un moyen simple de faire cela? J'ai essayé de résoudre le problème en utilisant les modèles de C et de la délégation, mais ne pas trop loin. J'espère qu'il ya une solution simple à cela, et il est probablement l'un que je viens oublié.

Je vous remercie de toute aide que vous et des conseils gars ont.

Merci.

Était-ce utile?

La solution

Si vous n'êtes pas peur d'utiliser des modèles, vous pouvez faire votre fonction d'un modèle et utiliser SFINAE pour vérifier les deux 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) {
  ...
}

Cela va créer une méthode pour chaque type qui étend les deux interfaces de fonction (notez que l'astuce SFINAE n'est pas nécessaire pour que cela fonctionne, un modèle sans contrainte fonctionnerait, mais juste ne pas compiler lorsque vous passez un type qui ne fonctionne pas répondre aux exigences).

Une autre possibilité consiste à créer une interface IFeatureXY étendant à la fois, et l'utiliser dans les paramètres de fonction; ce qui a l'inconvénient que les types que font mettre en œuvre les deux interfaces, mais pas cette interface commune ne serait pas utilisable avec cette méthode.

En outre, vous pouvez passer deux arguments à la fonction, une par interface, et exigent qu'ils sont des pointeurs vers le même objet; c'est fragile, mais il pourrait être durci en faisant une classe de modèle pour tenir les deux pointeurs - par exemple. product_type<IFeatureX*, IFeatureY*>, qui serait initialisé par le seul objet en question et qui détiendrait les deux types.

En Java, vous pourriez probablement faire la même chose avec des variables de type bornées (si elles permettent de bornes multiples, je ne suis pas sûr maintenant).

Autres conseils

La première chose à faire est de demander si vous essayez de faire quelque chose qui ne peut être exprimé simplement, et si oui, demandez-vous si elle vaut vraiment la peine?

Étant donné que vous ne pouvez pas trouver un modèle plus simple de ce que vous voulez, vous allez avoir besoin de penser sur les dépendances entre les options. Si vous pouvez utiliser la fonction X indépendamment de fonction Y, puis faire des interfaces indépendantes ou classes virtuelles pures (en fonction de la langue.)

Si vous ne pouvez pas les utiliser de façon indépendante, faire une classe qui comprend à la fois; demandez-vous pourquoi vous voulez FeatureX et FeatureY comme des interfaces distinctes, car ce modèle d'utilisation suggère qu'ils ne sont pas indépendants, après tout.

Bien qu'il existe des moyens d'ajouter des fonctionnalités complètement disparates, vous voudrez peut-être penser à la portée de ces fonctionnalités ajoutées. Vont-ils être liés à votre bibliothèque principale de classe? (On pourrait dire que si elles ne sont pas ils ne devraient pas faire partie de celui-ci)

Si elles ont suffisamment en commun pour justifier l'ajout de fonctionnalités, vous pouvez chercher ( http : //en.wikipedia.org/wiki/Decorator_pattern ). Il vous permet de contourner certains des problèmes déglingués de faire les choses comme ça.

Si vous voulez le faire en ot c ++, qu'en héritage multiple?

Peut-être que vous êtes trop à grains fins. Considérons une classe numérique - vous pouvez effectuer la multiplication, division, addition, soustraction, etc. Cependant, vous ne pas créer des interfaces distinctes pour chacune de ces opérations - vous devez créer une interface appelée SupportsArithmetic (ou autre) qui les couvrait tous

WCF a tendance très belle façon de déterminer si un objet prend en charge une interface (ou classe) à l'aide 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();
}

De cette façon, vous pouvez interroger votre objet pour une inteface. Une méthode similaire est utilisée dans COM + IUnknown :: QueryInterface ( ) .

Pourquoi avez-vous besoin d'interfaces? Utilisez des modèles:

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

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

Utilisation:

SomeClass x; // object with only X feature
some_function( x ); // compile time error, because featureY() doesn't exists
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top