2010-10-02 1 views
0

J'ai peu de problème de conception: j'ai une usine qui va créer un objet avec un type ou un autre type. Mais l'exigence de mon client est de donner (alimenter) les données (via des méthodes de définition) du monde extérieur à la classe concrète de type-1 et non de type-2.Comment puis-je créer une usine? Le client peut définir des données pour des méthodes qui ne sont pas définies dans l'interface? (Problème de conception)

Si je place ces méthodes de setter dans l'interface, celles-ci doivent être implémentées avec force dans les deux classes concrètes. Ce n'est pas mon exigence. Je veux nourrir 1 type de données pour 1er type (certains setters) et que vous voulez donner un autre type de données pour un autre type (probablement différents setters autres que ce qui est contenu par type précédent.)

par exemple

 class ISubjectExecutor 
    { 
     public: 
     virtual void ISUBJECTEXECUTOR_EXPORTS_API Execute()=0; 
    }; 

    class COMExecutor: public ISubjectExecutor 
    { 
     public: 
    virtual void Execute()=0; 
      void setCLSID(); 
      void setGuids(); 

    }; 
    class Win32Executor : public IWin32Executor 
    { 
     public:    
     virtual void Execute()=0; 
      void setFilePath(); 

    }; 

Maintenant, je ne peux pas utiliser le pointeur de ISubjectExecutor (* pSubjectExecutor) pour appeler les méthodes setter de Win32Executor ou COMExecutor sur mon choix à tout moment après avoir reçu le pointeur (ISubjectExecutor) de l'usine. Parce que tous ces setters n'existent jamais à l'intérieur de l'interface ISubjectExecutor, et vous ne pouvez accéder à aucune méthode qui ne soit jamais contenue dans l'interface et qui existe dans une implémentation concrète.

Comment faire pour résoudre ce problème de conception à résoudre.?

Cordialement Hassan

+0

Si le client sait déjà s'il veut appeler 'setCLSID()/setGuids()' ou 'setFilePath()' sur l'objet retourné en usine, alors il connaît déjà le type concret de l'objet, donc il peut De même, il suffit de baisser le pointeur vers 'COMExecutor' (si le premier) ou' Win32Executor' (si ce dernier). Dans ce cas, il est inutile d'utiliser une usine (ou du moins aucun avantage de conception). –

+1

Mon commentaire ci-dessus s'applique si vous souhaitez appeler des setters sur l'objet renvoyé par l'usine. Une meilleure conception consisterait à transmettre différents paramètres à l'usine pour que l'objet créé et renvoyé à vous ait déjà ces propriétés définies. –

Répondre

0

Vous pouvez définir une ou plusieurs pures méthodes virtuelles dans votre classe de base qui permet à une propriété à définir par étiquette/valeur (avec des types appropriés pour la valeur, et un ENUM pour l'étiquette). Ensuite, les classes dérivées implémenter du code pour le sous-ensemble de valeurs de balises qu'elles prennent en charge, et peut-être jeter une sorte d'exception "non supportée" (ou retourner false?) Si elles sont appelées pour traiter une propriété qu'elles ne supportent pas. Ici j'utilise std :: string pour représenter la valeur mais vous pouvez avoir besoin d'un type différent, ou d'autres surcharges.

class ISubjectExecutor 
{ 
    public: 
    virtual void ISUBJECTEXECUTOR_EXPORTS_API Execute()=0; 
    virtual void SetProperty(const Tag tag, const std::string& value) = 0; 

    // full list of tags in all subclasses 
    enum Tag { 
    Guids, 
    FilePath, 
    CLSID 
    };  
}; 



class COMExecutor: public ISubjectExecutor 
{ 
    public: 
    virtual void Execute()=0; 

    // Valid tags are Guids, CLSID 
    virtual void SetProperty(const Tag tag, const std::string& value); 

}; 
class Win32Executor : public IWin32Executor 
{ 
    public:    
    virtual void Execute()=0; 

    // Valid tags are FilePath 
    virtual void SetProperty(const Tag tag, const std::string& value); 
}; 

Il est maintenant légal d'appeler SetProperty par un pointeur vers ISubjectExecutor.

Questions connexes