Question

Supposons que nous ayons une Element classe abstraite dont les classes Triangle et Quadrilateral proviennent de.

Supposons encore que ces classes sont utilisées en conjonction avec des méthodes d'interpolation qui dépendent de la forme de l'élément. Donc, en gros, nous créons une InterpolationElement de classe abstraite dont nous tirons InterpolationTriangle et InterpolationQuadrilateral.

Ensuite, pour inclure la fonctionnalité d'interpolation dans les classes de Triangle et Quadrilateral, nous ajoutons un membre de données const référence en classe Element de type InterpolationElement, qui est:

class Element
{
public:
    Element(const InterpolationElement& interp);

    const InterpolationElement& getInterpolation() const;

private:
    const InterpolationElement& interpolation;
};

Nous avons ensuite créer une méthode (telle que décrite par Scott Meyers, Effective C ++) qui instancier un objet statique locale de InterpolationTriangle de classe comme

const InterpolationTriangle& getInterpolationTriangle()
{
    static InterpolationTriangle interpolationTriangle;

    return interpolationTriangle;
}

Alors que Triangle de classe peut être construit comme:

class Triangle : public Element
{
public:
    Triangle() : Element( getInterpolationTriangle() ) {}
};

Voici ma question: cette approche est correcte afin d'intégrer des méthodes d'interpolation sur mon Element de classe? Est-ce utilisé dans des scénarios professionnels?

Je pourrais mettre en œuvre directement toutes les méthodes d'interpolation sur la classe Element (comme virtuelle pure) et passer outre, dans les classes dérivées Triangle et Quadrilateral. Cependant, cette approche me semble être lourd, car chaque fois que je dois améliorer ou mettre en œuvre de nouvelles fonctionnalités d'interpolation, je dois le faire sur ces classes. De plus, les classes deviennent de plus en plus grandes (plusieurs méthodes) en utilisant cette approche.

Je voudrais vous entendre quelques conseils et commentaires

Merci à l'avance.


Détails supplémentaires:

class InterpolationElement
{
public:
    InterpolationElement();

    virtual double interpolationMethod1(...) = 0;
                      :
    virtual double interpolationMethodN(...) = 0;
}

class InterpolationTriangle : public InterpolationElement
{
public:
    InterpolationTriangle () {}

    virtual double interpolationMethod1(...) { // interpolation for triangle }
                      :
    virtual double interpolationMethodN(...) { // interpolation for triangle }
}

class InterpolationQuadrilateral : public InterpolationElement
{
public:
    InterpolationTriangle () {}

    virtual double interpolationMethod1(...) { // interpolation for quadrilateral}
                      :
    virtual double interpolationMethod1(...) { // interpolation for quadrilateral}
}
Était-ce utile?

La solution

Les classes sont utilisées conjointement avec interpolation méthodes . Pourquoi ces méthodes doivent être dans un objet singleton? Le singleton ici semble très problématique.

class Element
{
public:
    virtual double interpolationMethod1(...) = 0;
                  :
    virtual double interpolationMethodN(...) = 0;

};

class Triangle : public Element
{
public:
    virtual double interpolationMethod1(...) { // interpolation for triangle }
                  :
    virtual double interpolationMethodN(...) { // interpolation for triangle }
}

En outre, bienvenue à SO!

Autres conseils

Il rappelle une question que je lui avais répondu ici . La même idée de la séparation des données conteneurs et les stratégies.

Il y a un petit problème avec votre proposition: vous avez ajouté une méthode d'interpolation associée à votre classe de base et vous avez changé le constructeur ...

Alors tout d'abord, si vous souhaitez le faire de cette façon, voici comment vous devriez le faire:

class Element
{
public:

private:
  // similar signature to a `clone` method
  virtual InterpolationElement* interpolation() const = 0;
};

class Triangle
{
public:

private:
  virtual InterpolationTriangle* interpolation() const
  {
    return new InterpolationTriangle();
  }
};

Il y a 2 avantages ici:

  • Il est plus nécessaire de changer le constructeur de chacun des objets dérivés
  • L'objet de la stratégie est plus const, ce qui lui permet de maintenir l'état pendant le calcul ... comme une référence à l'objet courant étant interpolées.

Cependant, cela nécessite encore changer la classe Element, et chacune de ses classes dérivées. N'êtes-vous pas pris la peine;)

Eh bien, il est temps (pour une fois) de faire appel à un motif de conception. Visitor

Il est un peu différent de l'idée de stratégie, en se fondant sur l'envoi double pour travailler correctement. Cependant, il vous permet de modifier la hiérarchie des Elements UNE FOIS (avec une méthode de accept), puis d'ajouter autant d'opérations que vous le souhaitez. Et ce qui est grand.

Vous pouvez toujours gâcher un peu avec des modèles. D'abord, nous avons une classe supérieure.

class Element {
    public:
        virtual void calculate() const = 0;
};

... mais nous avons aussi une classe au milieu de la hiérarchie qui est en fait un modèle. Modèle ne peut pas être la classe de niveau supérieur, en tant que modèles avec différents paramètres sont différentes classes. L'idée est que nous donnons une classe d'interpolation en tant que paramètre de type à l'élément.

template <typename Interpolation>
class Element_Impl : public Element {
    protected:
        Interpolation m_interpolation;
};

Et les classes d'interpolation. Avis, ils ne sont pas frères et soeurs, parce qu'ils ne ont pas besoin.

class InterpolationTriangle {
    public:
        double interpolate(double a, double b) const {
            std::cout << "interpolation triangle" << std::endl;
        }
};
class InterpolationQuadrilateral {
    public:
        double interpolate(double a, double b) const {
            std::cout << "interpolation quadrilateral" << std::endl;
        }
};

Et enfin, les éléments réels de la petite et la procédure principale.

class Triangle : public Element_Impl<InterpolationTriangle> {
    public:
        void calculate() const {
            m_interpolation.interpolate(1.0, 2.0);
        }
};
class Quadrilateral : public Element_Impl<InterpolationQuadrilateral> {
    public:
        void calculate() const {
            m_interpolation.interpolate(2.0, 3.0);
        }
};
int main() {
    const Element &a = Triangle();
    const Element &b = Quadrilateral();
    a.calculate();
    b.calculate();
}

Résumé:

  • vous pouvez facilement changer la classe d'interpolation pour chaque élément si nécessaire.
  • il n'y a pas de double accès vtable (d'abord pour le calcul de l'élément et des méthodes intepolate de InterpolationElement) comme dans l'exemple de Matthieu. Chaque élément sait au moment de la compilation quelle classe interpolation qu'il utilise.
  • Element_Impl est un peu moche, mais il nous sauve de copypasta. Vous pouvez étendre encore plus loin en mettant en place des enveloppes de méthode d'interpolation
  • http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

La première consiste à utiliser des méthodes statiques, et la définition d'une enveloppe en Element_Impl -. Encore que dans un seul endroit

class Element {
    public:
        virtual void calculate() const = 0;
};

template <typename Interpolation>
class Element_Impl : public Element {
    protected:
        void interpolate(double, double) const {
            Interpolation::interpolate(1, 1);
        }
};

class InterpolationTriangle {
    public:
        static double interpolate(double a, double b) {
            std::cout << "interpolation triangle" << std::endl;
        }
};

class InterpolationQuadrilateral {
    public:
        static double interpolate(double a, double b) {
            std::cout << "interpolation quadrilateral" << std::endl;
        }
};

class Triangle : public Element_Impl<InterpolationTriangle> {
    public:
         void calculate() const {
            interpolate(1.0, 2.0);
        }
};

class Quadrilateral : public Element_Impl<InterpolationQuadrilateral> {
    public:
        void calculate() const {
            interpolate(2.0, 3.0);
        }
};

int main() {
    const Element &a = Triangle();
    const Element &b = Quadrilateral();

    a.calculate();
    b.calculate();
}

Qu'est-ce que vient d'abord à mon avis est le GoF Design Motif visiteur

D'après ce que je comprends de votre problème, ce modèle est conçu pour résoudre exactement ce problème.

Chaque objet visiteur définit une technique d'interpolation ou un algorithme à appliquer à votre objet.

Ainsi la classe Element ne se développe pas du tout avec chaque nouvelle fonctionnalité. Une fois en place, le modèle des visiteurs permet de toucher sans functionnality Enrich à la définition de la classe de base.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top