Estoy tratando de conseguir mi cabeza alrededor de la Mixin concepto, pero me parece que no puede entender lo que es.
La manera en que yo veo es que es una manera de ampliar las capacidades de una clase mediante la herencia.
He leído que la gente se refiere a ellos como «abstracto subclases». ¿Alguien puede explicar por qué?

Te agradecería si a usted le explique su respuesta basándose en el siguiente ejemplo (de una de mis conferencias presentaciones de diapositivas):
¿Cuáles son los Mixins (como concepto)

  • Un marco que hace un uso intensivo de los mixins se Apache Tapestry para aplicaciones web de Java. Lea la documentación y ver algunos ejemplos en la Galería y tal vez usted será capaz de ver los paralelismos/patrones de lo que están viendo en el ejemplo de C++. Aquí hay un enlace: tapestry.apache.org/component-mixins.html
  • Estoy totalmente pensó que estaban hablando acerca de Ruby con sólo una mirada del título…
InformationsquelleAutor Shookie | 2013-09-12

6 Comentarios

  1. 115

    Antes de entrar en lo que es un mix en el que está, es útil para describir los problemas que está tratando de resolver. Digamos que usted tiene un montón de ideas o conceptos que están tratando de modelo. Pueden estar relacionadas de alguna manera pero son ortogonales para la mayor parte, lo que significa que pueden valerse por sí mismos de forma independiente el uno del otro. Ahora usted puede ser que este modelo a través de la herencia y tener cada uno de esos conceptos que se derivan de algunos comunes de la interfaz de la clase. A continuación, se proporcionan métodos concretos en la derivada de la clase que implementa la interfaz.

    El problema con este enfoque es que este diseño no ofrece ninguna clara e intuitiva manera de tomar cada una de esas clases concretas y combinarlos juntos.

    La idea con mix-ins es proporcionar un montón de primitivas de clases, donde cada uno de ellos modelos básicos ortogonal concepto, y será capaz de seguir juntos para componer más complejo clases con la funcionalidad que usted desea, algo como legos. La primitiva clases de sí mismos están destinados a ser utilizados como bloques de construcción. Esto es extensible ya que más tarde usted puede agregar otros primitivo clases a la colección sin afectar a los ya existentes.

    Volviendo a la de C++, una técnica para hacerlo es mediante el uso de plantillas y la herencia. La idea básica aquí es que usted conecte estos bloques de construcción juntos por la prestación de los mismos a través de los parámetros de una plantilla. Usted, a continuación, la cadena de ellos juntos, por ejemplo. a través de typedef, para formar un nuevo tipo que contiene la funcionalidad que usted desea.

    Tomando su ejemplo, digamos que queremos añadir una rehacer la funcionalidad en la parte superior. Así es como podría parecer:

    #include <iostream>
    using namespace std;
    
    struct Number
    {
      typedef int value_type;
      int n;
      void set(int v) { n = v; }
      int get() const { return n; }
    };
    
    template <typename BASE, typename T = typename BASE::value_type>
    struct Undoable : public BASE
    {
      typedef T value_type;
      T before;
      void set(T v) { before = BASE::get(); BASE::set(v); }
      void undo() { BASE::set(before); }
    };
    
    template <typename BASE, typename T = typename BASE::value_type>
    struct Redoable : public BASE
    {
      typedef T value_type;
      T after;
      void set(T v) { after = v; BASE::set(v); }
      void redo() { BASE::set(after); }
    };
    
    typedef Redoable< Undoable<Number> > ReUndoableNumber;
    
    int main()
    {
      ReUndoableNumber mynum;
      mynum.set(42); mynum.set(84);
      cout << mynum.get() << '\n';  //84
      mynum.undo();
      cout << mynum.get() << '\n';  //42
      mynum.redo();
      cout << mynum.get() << '\n';  //back to 84
    }

    Te darás cuenta de que hice un par de cambios de su original:

    • Las funciones virtuales realmente no son necesarios aquí porque sabemos exactamente lo que nuestro compuesto por clase es de tipo en tiempo de compilación.
    • He añadido un defecto value_type para la plantilla de la segunda param para hacer que su uso es menos engorroso. De esta manera usted no tiene que seguir escribiendo <foobar, int> cada vez que usted se pega una pieza juntos.
    • En lugar de crear una nueva clase que hereda de las piezas, un simple typedef se utiliza.

    Tenga en cuenta que este está destinado a ser un ejemplo sencillo para ilustrar la mezcla en la idea. Así que no tomar en cuenta los casos de esquina y divertido de los usos. Por ejemplo, la realización de una undo sin siquiera poner un número probablemente no se comportan como se podría esperar.

    Como una nota al margen, también puede encontrar este artículo útil.

    • Este ejemplo es en realidad muy buena, de hecho, me lo lee y se sorprendió al encontrar que hicieron un montón de sentido lolol. Bien hecho compañero. Gracias.
    • Una nota para los lectores, void Number::set(int) y int Number::get() const deben ser virtual para obtener el mixin comportamiento cuando se utiliza un Number* puntero.
    • Mantenimiento de base de la clase set y get virtual tiene sentido porque entonces usted puede definir void doubler(Number &n){ n.set(n.get()*2); } y ser capaz de utilizar con deshacer y reundoable clases
    • Una sugerencia: cuando Number::value_type ya está definido que podría (y debería) ser utilizado también para Number::n, Number::get y Number::set.
    • Basado en mi entendimiento del razonamiento en este post, parece la misma línea de razonamiento se puede utilizar para decir que el nativo/tipos primitivos de cualquier lenguaje de programación (por ejemplo,int, std::string, char, etc en C++) son ellos mismos los mixins, derecho?
    • no, el el comportamiento de deshacer es el mixin

  2. 7

    Un mixin es una clase dessigned para proporcionar funcionalidad para otra clase, normalmente a través de una determinada clase que proporciona las características básicas que las necesidades de funcionalidad. Por ejemplo, considere el ejemplo:

    El mixin en este caso proporciona la funcionalidad de deshacer la operación de conjunto de una clase de valor. Esta habilidad se basa en la get/set funcionalidad proporcionada por una parametrización de la clase (El Number clase, en tu ejemplo).

    Otro ejemplo (Extraído de «Mixin de programación basado en C++«):

    template <class Graph>
    class Counting: public Graph {
      int nodes_visited, edges_visited;
    public:
      Counting() : nodes_visited(0), edges_visited(0), Graph() { }
      node succ_node (node v) {
        nodes_visited++;
        return Graph::succ_node(v);
      }
      edge succ_edge (edge e) {
        edges_visited++;
        return Graph::succ_edge(e);
      }
    ... 
    };

    En este ejemplo, el mixin proporciona la funcionalidad de contar vértices, dada una clase de gráfico que realiza trasversal de las operaciones.

    Comúnmente, en C++ los mixins son implementadas a través de la CRTP idioma. Este hilo podría ser una buena lectura sobre un mixin implementación en C++: ¿Qué es C++ Mixin Estilo?

    Aquí es un ejemplo de un mixin que toma ventaja de la CRTP lenguaje (Gracias a @Simples):

    #include <cassert>
    #ifndef NDEBUG
    #include <typeinfo>
    #endif
    
    class shape
    {
    public:
        shape* clone() const
        {
            shape* const p = do_clone();
            assert(p && "do_clone must not return a null pointer");
            assert(
                typeid(*p) == typeid(*this)
                && "do_clone must return a pointer to an object of the same type"
            );
            return p;
        }
    
    private:
        virtual shape* do_clone() const = 0;
    };
    
    template<class D>
    class cloneable_shape : public shape
    {
    private:
        virtual shape* do_clone() const
        {
            return new D(static_cast<D&>(*this));
        }
    };
    
    class triangle : public cloneable_shape<triangle>
    {
    };
    
    class square : public cloneable_shape<square>
    {
    };

    Este mixin proporciona la funcionalidad de copia heterogénea a un conjunto (jerarquía) de clases de formas.

    • El ejemplo no es CRTP a todos.
    • uy, eso es cierto 🙂
    • Pero me gustó tu comentario refiriéndose a CRTP. Debido a que los mixins son aproximados con CRTP en C++.
    • sí, es por eso que he publicado el comentario. Pero como habrán notado, el OP ejemplo no uso CRTP a todos. Es por eso que he quitado el comentario posterior.
    • ¿puede explicar por qué la gente la llama «la herencia sin sub-tipo de polimorfismo»? Todavía no estoy del todo seguro de que entender cómo esto es diferente de una clase abstracta que añade funcionalidad a todas las clases derivadas.
    • En CRTP la base de la clase es una plantilla que parece base<derived>, así que usted no puede tener un contenedor de base* objetos. También, una clase abstracta se utiliza virtual función que implican la sobrecarga de tiempo de ejecución; con CRTP utilizar static_cast para llamar a funciones miembro de la clase derivada que se resuelven de forma estática en tiempo de compilación.
    • Alguien tiene un buen ejemplo de la vida real que es fácil de comprender, iba a terminar de esta respuesta y un conjunto de comentarios bien creo.
    • ok, un ejemplo
    • Ejemplo de un CRTP mixin: ideone.com/V7MsAS
    • gracias, he añadido que a la respuesta. Su ejemplo se proporciona la habilidad de «ser cloneable» a una clase, ¿verdad? copia Heterogénea es el término correcto? No estoy seguro.
    • Permite definir clases con un es una relación con el shape clase, pero que derivan de cloneable_shape implementa automáticamente la clone función miembro para usted, así que usted no tiene que escribir a ti mismo para cada clase que se deriva.
    • eso es lo que he entendido, pero no lo hice del todo seguro acerca del término. Gracias de todos modos

  3. 5

    Me gusta la respuesta de greatwolf, pero le ofrecemos un punto de precaución.

    greatwolf declaró, «Las funciones virtuales realmente no son necesarios aquí porque sabemos exactamente lo que nuestro compuesto por clase es de tipo en tiempo de compilación.» Desafortunadamente, no se puede ejecutar en alguna comportamiento incoherente si usted utiliza su objeto polymorphically.

    Me deja modificar la función principal de su ejemplo:

    int main()
    {
      ReUndoableNumber mynum;
      Undoable<Number>* myUndoableNumPtr = &mynum;
    
      mynum.set(42);                //Uses ReUndoableNumber::set
      myUndoableNumPtr->set(84);    //Uses Undoable<Number>::set (ReUndoableNumber::after not set!)
      cout << mynum.get() << '\n';  //84
      mynum.undo();
      cout << mynum.get() << '\n';  //42
      mynum.redo();
      cout << mynum.get() << '\n';  //OOPS! Still 42!
    }  

    Por lo que el «conjunto» de la función virtual, el de la invalidación de la llamada y el comportamiento incoherente de arriba no va a ocurrir.

  4. 0

    Esto funciona de la misma como una interfaz y tal vez más, así como un resumen, pero las interfaces son más fáciles de obtener por primera vez.

    Que resuelve muchos problemas, pero uno encontrar en el desarrollo de que se ve mucho es api externas. imaginar esto.

    Tiene una base de datos de los usuarios, la base de datos que tiene una determinada forma de acceder a sus datos.
    ahora imagine que tiene facebook, que también tiene una cierta forma de tener acceso a sus datos (api).

    en cualquier punto de su aplicación para que se ejecute el uso de datos de facebook o su base de datos. entonces lo que hacen es crear una interfaz que dice: «cualquier cosa que implementa me va a duda, tiene los siguientes métodos de» ahora puede implementar la interfaz en la aplicación…

    ya que la interfaz de las promesas de que la implementación de repositorios tienen los métodos declarados en ellos, usted sabe que, donde y cuando usted usar la interfaz de la aplicación, si usted cambia los datos, siempre va a tener los métodos que se están definiendo y por lo tanto han de datos para trabajar.

    Hay muchas más capas a este patrón de trabajo, pero la esencia es que es bueno, porque los datos o de otros compuestos de elementos convertido en una gran parte de su solicitud, y si cambian sin que usted lo sepa, su aplicación puede romper 🙂

    He aquí algunos pseudo código.

    interface IUserRepository
    {
        User GetUser();
    }
    
    class DatabaseUserRepository : IUserRepository
    {
        public User GetUser()
        {
            //Implement code for database
        }
    }
    
    class FacebookUserRepository : IUserRepository
    {
        public User GetUser()
        {
            //Implement code for facebook
        }
    }
    
    class MyApplication
    {
        private User user;
    
        MyApplication( IUserRepository repo )
        {
            user = repo;
        }
    }
    
    //your application can now trust that user declared in private scope to your application, will have access to a GetUser method, because if it isn't the interface will flag an error.
    • El código parece java, y no como en c++. También, cómo son los mixins diferente de lo normal, las clases abstractas?
    • ah bueno, yo C#, PHP y C++… de hecho, me dijeron que son muy similares a lo abstracto, pero me parece que es más difícil explicar su uso… teniendo en cuenta que tengo todavía los uso un montón y un montón :). Siempre que se intenta llegar a una buena herencia ejemplo, que me hacen llorar. El código fue demostrar más fácil con el palabreo de la sintaxis, pero no es real código, pseudo dije 🙂 espero que alguien responda que es mucho más claro, pero personalmente me gusta más prolijo respuestas, me parece más útil y un buen ejemplo de la vida real también ^_^
    • Ok, esto me hizo pensar. Después de leer esto, he buscado en la red, y no podía encontrar una explicación decente. Yo todavía no lo entiendo ¿cuáles son los mixins :/
    • Entiendo que tienes buenas intenciones, pero su explicación hace que la imagen más borrosa de lo que ya era. Por no mencionar el hecho, que se perdió el «en C++» parte.
  5. 0

    Para entender el concepto olvidar clases por un momento. Pensar (más popular) de JavaScript. Donde los objetos son matrices dinámicas de métodos y propiedades. Se puede llamar por su nombre como un símbolo o un literal de cadena. ¿Cómo podría implementar que en el estándar de C++ en un año 2018? No fácilmente. Pero que es el núcleo del concepto. En JavaScript se puede añadir y eliminar (también conocido como mix-in) siempre y todo lo que uno desea. Muy importante: No hay ninguna clase de herencia.

    Ahora en C++. El estándar de C++ tiene todo lo que usted necesita, no ayuda como una declaración aquí. Obviamente no voy a escribir un lenguaje de secuencias de comandos con el fin de aplicar la mezcla en el uso de C++.

    Sí, este es un buen artículo , pero para que la inspiración sólo. CRTP no es una panacea. Y también el llamado enfoque académico es aquí, también (en esencia) CRTP base.

    Antes de la votación de esta respuesta tal vez considerar mi p.o.c. código de varita cuadro 🙂

Dejar respuesta

Please enter your comment!
Please enter your name here