Pregunta

Supongamos que tenemos un Element clase abstracta de la que Triangle clases y Quadrilateral se derivan de.

Supongamos ahora de que estas clases se utilizan en conjunción con métodos de interpolación que dependen de la forma del elemento. Así que, básicamente, creamos un InterpolationElement clase abstracta de la que deriva InterpolationTriangle y InterpolationQuadrilateral.

A continuación, para incluir la funcionalidad de interpolación en las clases Triangle y Quadrilateral, añadimos un miembro de datos const-referencia en Element clase de tipo InterpolationElement, que es:

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

    const InterpolationElement& getInterpolation() const;

private:
    const InterpolationElement& interpolation;
};

a continuación, crear un método (tal como se describe por Scott Meyers, eficaz C ++) que instanciar un objeto estático local del InterpolationTriangle clase como

const InterpolationTriangle& getInterpolationTriangle()
{
    static InterpolationTriangle interpolationTriangle;

    return interpolationTriangle;
}

Para que Triangle clase puede ser construido como:

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

Aquí está mi pregunta: ¿Es este enfoque correcto con el fin de incorporar métodos de interpolación en mi Element clase? Se utiliza en esta escenarios profesionales?

I podía aplicar directamente a todos los métodos de interpolación sobre Element clase (como puro virtual) y la anulación de ellos en el Triangle clases derivadas y Quadrilateral. Sin embargo, este enfoque parece a mí ser engorroso, ya que cada vez que necesitan mejorar o implementar nuevas funcionalidades de interpolación que tendría que hacer eso en estas clases. Por otra parte, las clases se hacen más grandes y más grandes (muchos métodos) utilizando este enfoque.

Me gustaría saber de usted algunos consejos y comentarios

Gracias de antemano.


Detalles adicionales:

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}
}
¿Fue útil?

Solución

Las clases se utilizan junto con la interpolación métodos . ¿Por qué esos métodos necesitan estar en un objeto Singleton? El Singleton aquí se ve muy problemático.

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 }
}

Además, la bienvenida a SO!

Otros consejos

Esto es una reminiscencia de una pregunta que me había respondido aquí . La misma idea acerca de la separación de los contenedores de datos y las estrategias.

Hay un pequeño problema con su propuesta: que haya añadido un método de interpolación relacionada a su clase base y que ha cambiado el constructor ...

Así que en primer lugar, si desea hacerlo de esta manera, así es como debe hacerlo:

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();
  }
};

Hay 2 ventajas aquí:

  • Es ya no es necesario cambiar el constructor de cada uno de los objetos derivados
  • El objeto estrategia hay const más tiempo, lo que le permite mantener el estado durante el cálculo ... como una referencia al objeto actual que está siendo interpolado.

Sin embargo, esto aún requiere para cambiar la clase Element, y cada una de sus clases derivadas. ¿No te molesta;?)

Bueno, es el momento (por una vez) para llamar a un patrón de diseño:. Visitor

Es un poco diferente de la idea de estrategia, basándose en el doble de despacho para que funcione correctamente. Sin embargo, le permite modificar la jerarquía de Elements vez (con un método accept) y luego añadir tantas operaciones como desee. Y lo que es grande.

Siempre puede meterse un poco con las plantillas. En primer lugar tenemos una clase superior.

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

... pero entonces también tenemos una clase en el medio de la jerarquía que en realidad es una plantilla. Plantilla no puede ser la clase de nivel superior, como plantillas con diferentes parámetros son diferentes clases. La idea es que le damos una clase de interpolación como un parámetro de tipo de elemento.

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

Y interpolación. Aviso, no son hermanos, ya que no necesitan.

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;
        }
};

Y, finalmente, los elementos reales y la pequeña procedimiento principal.

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();
}

Resumen:

  • Puede cambiar fácilmente la clase de interpolación para cada elemento si es necesario.
  • no hay acceso vtable doble (primero para calcular de Element y luego para los métodos de intepolate de InterpolationElement) como en el ejemplo de la Matthieu. Cada elemento conoce en tiempo de compilación qué clase de interpolación que está utilizando.
  • Element_Impl es un poco feo, pero nos salva de copypasta. Se puede ampliar aún más mediante la implementación de las envolturas método de interpolación
  • http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Una forma es utilizar los métodos estáticos, y la definición de un envoltorio en Element_Impl -. Todavía se encuentra en un lugar

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();
}

Lo primero que viene a la mente es el patrón GoF Diseño Visitante

Por lo que entiendo de su problema, este patrón se concibe exactamente a resolver este problema.

Cada objeto de Visitantes define una técnica de interpolación, o un algoritmo para aplicar a su objeto.

Así, la clase de elemento no crece en absoluto con cada nueva Funcionalidad. Una vez en su lugar, el patrón del visitante permite enriquecer Funcionalidad sin tocar a la definición de clase base.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top