Wat is een mixin en waarom zijn ze nuttig?

in “Programmering Python “, MARK LUTZ noemt” Mixins “. Ik kom uit een C / C++ / C #-achtergrond en ik heb de term niet eerder gehoord. Wat is een mixin?

lezen tussen de lijnen van Dit voorbeeld ( Waar ik aan heb gekoppeld omdat het vrij lang is), ik veronderstel dat het een geval is van het gebruik van meerdere overerving om een ​​klasse uit te breiden in tegenstelling tot ‘juiste’ subclassificatie. Is dit juist?

Waarom zou ik dat willen doen in plaats van de nieuwe functionaliteit in een subklasse te zetten? WAAROM ZOU EEN MIXIN / MULTIER OHERITIE-aanpak beter zijn dan het gebruik van de compositie?

Wat scheidt een mix van meerdere erfenis? Is het gewoon een kwestie van semantiek?


1, Autoriteit 100%

Een mixin is een speciaal soort meerdere erfenis. Er zijn twee belangrijke situaties waarin mengels worden gebruikt:

  1. U wilt veel optionele functies bieden voor een klasse.
  2. U wilt een bepaalde functie in veel verschillende klassen gebruiken.

Voor een voorbeeld van nummer één, overweeg dan Werkzeug’s verzoek en reactiesysteem . Ik kan een gewone oude aanvraagobject maken door te zeggen:

from werkzeug import BaseRequest
class Request(BaseRequest):
    pass

Als ik Accept-header-ondersteuning wil toevoegen, zou ik dat

maken

from werkzeug import BaseRequest, AcceptMixin
class Request(AcceptMixin, BaseRequest):
    pass

Als ik een aanvraagobject wilde maken dat accept headers, etags, authenticatie en user-agent-ondersteuning ondersteunt, zou ik dit kunnen doen:

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin
class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

Het verschil is subtiel, maar in de bovenstaande voorbeelden zijn de mixin-klassen niet gemaakt om op zichzelf te staan. Bij meer traditionele meervoudige overerving zou de AuthenticationMixin(bijvoorbeeld) waarschijnlijk meer op Authenticatorlijken. Dat wil zeggen, de klas zou waarschijnlijk ontworpen zijn om op zichzelf te staan.


Antwoord 2, autoriteit 32%

Ten eerste moet u er rekening mee houden dat mixins alleen bestaan in talen met meerdere overervingen. Je kunt geen mixin doen in Java of C#.

Kortom, een mixin is een op zichzelf staand basistype dat beperkte functionaliteit en polymorfe resonantie biedt voor een onderliggende klas. Als je in C# denkt, denk dan aan een interface die je niet echt hoeft te implementeren omdat deze al is geïmplementeerd; u erft er gewoon van en profiteert van de functionaliteit ervan.

Mixins hebben doorgaans een beperkte reikwijdte en zijn niet bedoeld om te worden uitgebreid.

[edit — waarom:]

Ik neem aan dat ik moet uitleggen waarom, aangezien je erom vroeg. Het grote voordeel is dat u het niet steeds opnieuw zelf hoeft te doen. In C# is de grootste plaats waar een mixin kan profiteren van het verwijderingspatroon . Telkens wanneer u IDisposable implementeert, wilt u bijna altijd hetzelfde patroon volgen, maar u schrijft en herschrijft uiteindelijk dezelfde basiscode met kleine variaties. Als er een uitschuifbare Disposal-mixin zou zijn, zou je jezelf een hoop extra typen kunnen besparen.

[bewerk 2 — om je andere vragen te beantwoorden]

Wat onderscheidt een mixin van meervoudige overerving? Is het alleen een kwestie van semantiek?

Ja. Het verschil tussen een mixin en standaard meervoudige overerving is slechts een kwestie van semantiek; een klasse met meervoudige overerving kan een mixin gebruiken als onderdeel van die meervoudige overerving.

Het punt van een mixin is om een type te creëren dat via overerving met elk ander type kan worden “gemengd” zonder het overervende type te beïnvloeden, terwijl het toch een aantal nuttige functionaliteit biedt voor dat type.

Nogmaals, denk aan een interface die al is geïmplementeerd.

Persoonlijk gebruik ik geen mixins, omdat ik me voornamelijk ontwikkel in een taal die ze niet ondersteunt, dus ik vind het heel moeilijk om een fatsoenlijk voorbeeld te bedenken dat dat “ahah!” momentje voor jou. Maar ik zal het opnieuw proberen. Ik ga een gekunsteld voorbeeld gebruiken — de meeste talen bieden de functie al op de een of andere manier — maar dat zal hopelijk uitleggen hoe mixins moeten worden gemaakt en gebruikt. Hier gaat het:

Stel dat je een type hebt dat je wilt kunnen serialiseren van en naar XML. U wilt dat het type een “ToXML”-methode levert die een tekenreeks retourneert die een XML-fragment bevat met de gegevenswaarden van het type, en een “FromXML” waarmee het type zijn gegevenswaarden kan reconstrueren uit een XML-fragment in een tekenreeks. Nogmaals, dit is een gekunsteld voorbeeld, dus misschien gebruik je een bestandsstroom, of een XML Writer-klasse uit de runtime-bibliotheek van je taal… wat dan ook. Het punt is dat u uw object naar XML wilt serialiseren en een nieuw object uit XML wilt terughalen.

Het andere belangrijke punt in dit voorbeeld is dat je dit op een generieke manier wilt doen. U wilt niet voor elk type dat u wilt serialiseren een “ToXML”- en “FromXML”-methode moeten implementeren, u wilt een generieke manier om ervoor te zorgen dat uw type dit doet en dat het gewoon werkt. U wilt code hergebruik.

Als uw taal dit ondersteunt, kunt u de XmlSerializable-mixin maken om uw werk voor u te doen. Dit type zou de ToXML- en de FromXML-methoden implementeren. Het zou, met behulp van een mechanisme dat niet belangrijk is voor het voorbeeld, in staat zijn om alle benodigde gegevens te verzamelen van elk type waarmee het is gemengd om het XML-fragment te bouwen dat wordt geretourneerd door ToXML en het zou evengoed in staat zijn om die gegevens te herstellen wanneer FromXML is genaamd.

En… dat is het. Om het te gebruiken, zou je elk type dat moet worden geserialiseerd naar XML, overnemen van XmlSerializable. Telkens wanneer u dat type moest serialiseren of deserialiseren, riep u eenvoudig ToXML of FromXML aan. In feite, aangezien XmlSerializable een volwaardig type en polymorf is, zou je mogelijk een document-serializer kunnen bouwen die niets weet over je originele type, en die alleen, laten we zeggen, een reeks XmlSerializable-types accepteert.

Stel je nu voor dat je dit scenario voor andere dingen gebruikt, zoals het creëren van een mixin die ervoor zorgt dat elke klasse die het inlogt in logboeken elke methode-oproep, of een mixin die transactionaliteit biedt aan het type dat het mengt. De lijst kan gaan en Aan.

Als u alleen maar aan een mixin denkt als een klein basistype dat is ontworpen om een ​​kleine hoeveelheid functionaliteit aan een type toe te voegen, zonder anderszins dat type te beïnvloeden, dan bent u goudkleurig.

hopelijk. 🙂


3, Autoriteit 25%

Dit antwoord is bedoeld om Mixins te verklaren met voorbeelden dat zijn:

  • Self-contained : Short, zonder enige bibliotheken te weten om het voorbeeld te begrijpen.

  • in Python , niet in andere talen.

    Het is begrijpelijk dat er voorbeelden waren uit andere talen zoals Ruby, omdat de term veel vaker voorkomt in die talen, maar dit is een python draad.

Het beschouwt ook de controversiële vraag:

is meerdere erfenis nodig of niet om een ​​mixin te karakteriseren?

definities

Ik heb nog een citaat van een “gezaghebbende” bron zien zeggen dat het duidelijk is wat een mixin in Python is.

Ik heb 2 mogelijke definities van een mixin gezien (als ze moeten worden beschouwd als verschillend van andere soortgelijke concepten, zoals abstracte base-klassen), en mensen zijn het er niet mee eens over welke juist is.

De consensus kan variëren tussen verschillende talen.

Definitie 1: Geen meerdere overerving

Een mixin is een klasse zodanig dat een methode van de klasse een methode gebruikt die niet is gedefinieerd in de klasse.

Daarom is de klasse niet bedoeld om te worden geïnstantieerd, maar liever als basisklasse. Anders zou het exemplaar methoden hebben die niet kunnen worden gebeld zonder een uitzondering te verhogen.

Een beperking die sommige bronnen toevoegen, is dat de klasse geen gegevens mag bevatten, alleen methoden, maar ik zie niet in waarom dit nodig is. In de praktijk hebben veel bruikbare mixins echter geen gegevens en zijn basisklassen zonder gegevens eenvoudiger te gebruiken.

Een klassiek voorbeeld is de implementatie van alle vergelijkingsoperatoren van alleen <=en ==:

class ComparableMixin(object):
    """This class has methods which use `<=` and `==`,
    but this class does NOT implement those methods."""
    def __ne__(self, other):
        return not (self == other)
    def __lt__(self, other):
        return self <= other and (self != other)
    def __gt__(self, other):
        return not self <= other
    def __ge__(self, other):
        return self == other or self > other
class Integer(ComparableMixin):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i
assert Integer(0) <  Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) >  Integer(0)
assert Integer(1) >= Integer(1)
# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o 

Dit specifieke voorbeeld had kunnen worden bereikt via de functools.total_ordering()-decorateur, maar het spel hier was om het wiel opnieuw uit te vinden:

import functools
@functools.total_ordering
class Integer(object):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)

Definitie 2: meervoudige overerving

Een mixin is een ontwerppatroon waarin een methode van een basisklasse een methode gebruikt die hij niet definieert, en die methode is bedoeld om te worden geïmplementeerd door een andere basisklasse, niet door de afgeleide like in definitie 1.

De term mixin-klasseverwijst naar basisklassen die bedoeld zijn om in dat ontwerppatroon te worden gebruikt (TODO degenen die de methode gebruiken of degenen die deze implementeren?)

Het is niet eenvoudig om te beslissen of een bepaalde klasse een mixin is of niet: de methode kan gewoon worden geïmplementeerd op de afgeleide klasse, in welk geval we terug zijn bij definitie 1. Je moet rekening houden met de bedoelingen van de auteur.

Dit patroon is interessant omdat het mogelijk is om functionaliteiten te combineren met verschillende keuzes van basisklassen:

class HasMethod1(object):
    def method(self):
        return 1
class HasMethod2(object):
    def method(self):
        return 2
class UsesMethod10(object):
    def usesMethod(self):
        return self.method() + 10
class UsesMethod20(object):
    def usesMethod(self):
        return self.method() + 20
class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass
assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22
# Nothing prevents implementing the method
# on the base class like in Definition 1:
class C3_10(UsesMethod10):
    def method(self):
        return 3
assert C3_10().usesMethod() == 13

Geautoriseerde Python-voorvallen

In de officiële documentatie voor collections.abcwordt in de documentatie expliciet gebruik gemaakt van de term Mengmethoden.

Er staat dat als een klas:

  • implementeert __next__
  • erft van een enkele klasse Iterator

dan krijgt de klas gratis een __iter__mixin-methode.

Daarom, althans op dit punt van de documentatie, vereist mixin geen meervoudige overerving, en is het coherent met definitie 1.

De documentatie kan natuurlijk op verschillende punten tegenstrijdig zijn, en andere belangrijke Python-bibliotheken kunnen de andere definitie in hun documentatie gebruiken.

Deze pagina gebruikt ook de term Set mixin, wat duidelijk suggereert dat klassen zoals Seten IteratorMixin-klassen kunnen worden genoemd.

p>

In andere talen

  • Ruby: vereist duidelijk geen meervoudige overerving voor mixin, zoals vermeld in belangrijke naslagwerken zoals Ruby programmerenen de programmeertaal Ruby

  • C++: een virtualmethode die is ingesteld op =0is een pure virtuele methode.

    Definitie 1 valt samen met de definitie van een abstracte klasse (een klasse die een pure virtuele methode heeft).
    Die klasse kan niet worden geïnstantieerd.

    Definitie 2 is mogelijk met virtuele overerving: Meervoudige overerving van twee afgeleide klassen


Antwoord 4, autoriteit 5%

Ik beschouw ze als een gedisciplineerde manier om meervoudige overerving te gebruiken – omdat een mixin uiteindelijk gewoon een andere pythonklasse is die (misschien) de conventies volgt over klassen die mixins worden genoemd.

Mijn begrip van de conventies die gelden voor iets dat je een Mixin zou noemen, is dat een Mixin:

  • voegt methoden toe, maar geen instantievariabelen (klasseconstanten zijn OK)
  • erft alleen van object(in Python)

Op die manier beperkt het de potentiële complexiteit van meervoudige overerving en maakt het redelijk eenvoudig om de stroom van je programma te volgen door te beperken waar je moet kijken (vergeleken met volledige meervoudige overerving). Ze lijken op ruby-modules.

Als ik instantievariabelen wil toevoegen (met meer flexibiliteit dan toegestaan door enkele overerving), dan heb ik de neiging om voor compositie te gaan.

Dat gezegd hebbende, heb ik klassen met de naam XYZMixin gezien die wel instantievariabelen hebben.


Antwoord 5, autoriteit 4%

Wat onderscheidt een mixin van meervoudige overerving? Is het alleen een kwestie van semantiek?

Een mixin is een beperkte vorm van meervoudige overerving. In sommige talen verschilt het mechanisme voor het toevoegen van een mixin aan een klasse (in termen van syntaxis) enigszins van dat van overerving.

Vooral in de context van Python is een mixin een bovenliggende klasse die functionaliteit biedt aan subklassen, maar die niet bedoeld is om zelf te worden geïnstantieerd.

Wat je zou kunnen doen zeggen, “dat is gewoon meervoudige overerving, niet echt een mixin” is als de klasse die verward kan worden voor een mixin daadwerkelijk kan worden geïnstantieerd en gebruikt – dus het is inderdaad een semantische, en zeer reële, verschil.

Voorbeeld van meervoudige overerving

Dit voorbeeld, uit de documentatie, is een OrderedCounter:

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'
     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

Het subclasseert zowel de Counterals de OrderedDictuit de module collections.

Zowel Counterals OrderedDictzijn bedoeld om op zichzelf te worden geïnstantieerd en gebruikt. Door ze echter beide te subclasseren, kunnen we een teller hebben die is geordend en de code in elk object opnieuw gebruikt.

Dit is een krachtige manier om code opnieuw te gebruiken, maar het kan ook problematisch zijn. Als blijkt dat er een bug in een van de objecten zit, kan het onzorgvuldig repareren ervan een bug in de subklasse veroorzaken.

Voorbeeld van een mix

Mixins worden meestal gepromoot als de manier om codehergebruik te krijgen zonder mogelijke koppelingsproblemen die coöperatieve meervoudige overerving, zoals de OrderedCounter, zou kunnen hebben. Wanneer u mixins gebruikt, gebruikt u functionaliteit die niet zo nauw is gekoppeld aan de gegevens.

In tegenstelling tot het bovenstaande voorbeeld, is een mixin niet bedoeld om op zichzelf te worden gebruikt. Het biedt nieuwe of andere functionaliteit.

De standaardbibliotheek heeft bijvoorbeeld een aantal mixins in de socketserverbibliotheek.

Forking- en threadingversies van elk type server kunnen worden gemaakt
met behulp van deze mix-in klassen. ThreadingUDPServer is bijvoorbeeld:
als volgt gemaakt:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

De klasse mix-in komt eerst, omdat deze een methode overschrijft die is gedefinieerd in
UDPServer. Het instellen van de verschillende attributen verandert ook het gedrag van
het onderliggende servermechanisme.

In dit geval overschrijven de mixin-methoden de methoden in de UDPServerobjectdefinitie om gelijktijdigheid mogelijk te maken.

De overschreven methode lijkt process_requestte zijn en biedt ook een andere methode, process_request_thread. Hier is het van de broncode:

class ThreadingMixIn:
        """Mix-in class to handle each request in a new thread."""
        # Decides how threads will act upon termination of the
        # main process
        daemon_threads = False
        def process_request_thread(self, request, client_address):
            """Same as in BaseServer but as a thread.
            In addition, exception handling is done here.
            """
            try:
                self.finish_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
            finally:
                self.shutdown_request(request)
        def process_request(self, request, client_address):
            """Start a new thread to process the request."""
            t = threading.Thread(target = self.process_request_thread,
                                 args = (request, client_address))
            t.daemon = self.daemon_threads
            t.start()

een gekunsteld voorbeeld

Dit is een mixin die meestal is voor demonstratiedoeleinden – de meeste objecten zullen evolueren dan het nut van deze REP:

class SimpleInitReprMixin(object):
    """mixin, don't instantiate - useful for classes instantiable
    by keyword arguments to their __init__ method.
    """
    __slots__ = () # allow subclasses to use __slots__ to prevent __dict__
    def __repr__(self):
        kwarg_strings = []
        d = getattr(self, '__dict__', None)
        if d is not None:
            for k, v in d.items():
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        slots = getattr(self, '__slots__', None)
        if slots is not None:
            for k in slots:
                v = getattr(self, k, None)
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        return '{name}({kwargs})'.format(
          name=type(self).__name__,
          kwargs=', '.join(kwarg_strings)
          )

en gebruik zou zijn:

class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
    __slots__ = 'foo',
    def __init__(self, foo=None):
        self.foo = foo
        super(Foo, self).__init__()

en gebruik:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)

6, Autoriteit 4%

Mixins is een concept bij het programmeren waarin de klasse functionaliteiten biedt, maar het is niet bedoeld om te worden gebruikt voor instantiatie. Het hoofddoel van Mixins is om functionaliteiten te bieden die standalone zijn en het zou het beste zijn als de mixen zelf geen erfenis hebben met andere mixen en ook vermijden. In talen zoals Ruby, is er enkele directe taalondersteuning, maar voor Python is er niet. U kunt echter een meerklasse overerving gebruiken om de functionaliteit in Python uit te voeren.

Ik heb deze video http://www.youtube.com/watch?v=v_uki2nolem begrijpen de basis van mixins. Het is vrij handig voor een beginner om de basisprincipes van Mixins te begrijpen en hoe ze werken en de problemen waarmee u kunt ondergaan in de uitvoering ervan.

Wikipedia is nog steeds de beste: http://en.wikipedia.org/wiki/mixin


7

Ik denk dat er hier een goede verklaringen zijn geweest, maar ik wilde een ander perspectief bezorgen.

In Scala kunt u Mixins doen zoals hier is beschreven, maar wat is er erg interessant is dat de mixen eigenlijk ‘samengevoegd’ zijn om een ​​nieuw soort klasse te creëren om te erven. In wezen beërf je niet van meerdere klassen / mixins, maar eerder een nieuw soort klasse met alle eigenschappen van het mengsel om te erven van. Dit is logisch aangezien Scala gebaseerd is op de JVM waar multiple-overerving momenteel niet wordt ondersteund (vanaf Java 8). Dit mengklasse-type is trouwens een speciaal type dat een eigenschap in Scala wordt genoemd.

Het is doorgewikkeld op de manier waarop een klasse is gedefinieerd:
Klasse-newclass breidt FirstMixin uit met tweedeMixin met Th ThoneMixin

Ik weet niet zeker of de CPYTHON-tolk hetzelfde doet (Mixin Class-Samenstelling), maar ik zou niet verrast zijn. Ook, afkomstig van een C++ -achtergrond, zou ik geen ABC of ‘interface’ equivalent bellen aan een mixin – het is een vergelijkbaar concept, maar divergent in gebruik en implementatie.


8

Ik zou adviseren tegen mix-ins in nieuwe Python-code, als je een andere manier omheen kunt vinden (zoals compositie-in plaats van overerving of alleen monkey-patching-methoden in je eigen klassen) die is ‘ t veel meer moeite.

In oude klassen zou je mix-ins kunnen gebruiken om een paar methodes uit een andere klasse te halen. Maar in de wereld nieuwe stijl erft alles, zelfs de mix-in, van object. Dat betekent dat elk gebruik van meervoudige overerving natuurlijk MRO-problemenmet zich meebrengt .

Er zijn manieren om MRO met meerdere overervingen te laten werken in Python, met name de functie super(), maar het betekent dat je je hele klassenhiërarchie moet doen met super(), en het is aanzienlijk moeilijker om de stroom van controle.


Antwoord 9

Misschien helpen een paar voorbeelden.

Als je een klasse aan het bouwen bent en je wilt dat deze zich als een woordenboek gedraagt, kun je alle verschillende __ __-methoden definiëren die nodig zijn. Maar dat doet een beetje pijn. Als alternatief kunt u er een paar definiëren en (naast elke andere overerving) erven van UserDict.DictMixin(verplaatst naar collections.DictMixinin py3k). Dit heeft tot gevolg dat automatisch de rest van de woordenboek-API wordt gedefinieerd.

Een tweede voorbeeld: met de GUI-toolkit wxPython kun je lijstbesturingselementen maken met meerdere kolommen (zoals bijvoorbeeld de bestandsweergave in Windows Verkenner). Standaard zijn deze lijsten vrij eenvoudig. U kunt extra functionaliteit toevoegen, zoals de mogelijkheid om de lijst op een bepaalde kolom te sorteren door op de kolomkop te klikken, door over te nemen van ListCtrl en de juiste mixins toe te voegen.


Antwoord 10

Het is geen Python-voorbeeld, maar in de programmeertaal Dde term mixinwordt gebruikt om te verwijzen naar een constructie vrijwel op dezelfde manier gebruikt; een stapel dingen aan een klas toevoegen.

In D (wat overigens geen MI doet) wordt dit gedaan door een sjabloon (denk aan syntactisch bewuste en veilige macro’s en je komt in de buurt) in een scope in te voegen. Dit maakt het mogelijk om een enkele regel code in een klasse, struct, functie, module of wat dan ook uit te breiden naar een willekeurig aantal declaraties.


Antwoord 11

OP zei dat hij/zij nog nooit van mixin in C++ had gehoord, misschien omdat ze in C++ Curiously Recurring Template Pattern (CRTP) heten. @Ciro Santilli vermeldde ook dat mixin is geïmplementeerd via abstracte basisklasse in C++. Hoewel abstracte basisklasse kan worden gebruikt om mixin te implementeren, is het een overkill omdat de functionaliteit van een virtuele functie tijdens runtime kan worden bereikt met behulp van een sjabloon tijdens het compileren zonder de overhead van het opzoeken van virtuele tabellen tijdens runtime.

Het CRTP-patroon wordt hier

in detail beschreven

Ik heb het python-voorbeeld in het antwoord van @Ciro Santilli omgezet in C++ met de onderstaande sjabloonklasse:

   #include <iostream>
    #include <assert.h>
    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
        protected:
            ComparableMixin() {}
    };
    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };
int main() {
    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);
    return 0;
}

EDIT: Beveiligde constructor toegevoegd in ComparableMixin zodat deze alleen kan worden overgenomen en niet geïnstantieerd. Het voorbeeld bijgewerkt om te laten zien hoe een beveiligde constructor een compilatiefout veroorzaakt wanneer een object van ComparableMixin wordt gemaakt.


Antwoord 12

Misschien kan een voorbeeld van ruby helpen:

Je kunt de mixin Comparabletoevoegen en één functie "<=>(other)"definiëren, de mixin biedt al die functies:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

Het doet dit door <=>(other)aan te roepen en het juiste resultaat terug te geven.

"instance <=> other"retourneert 0 als beide objecten gelijk zijn, kleiner dan 0 als instancegroter is dan otheren meer dan 0 als othergroter is.


Antwoord 13

mixin biedt een manier om functionaliteit aan een klasse toe te voegen, d.w.z. je kunt interactief werken met methoden die in een module zijn gedefinieerd door de module in de gewenste klasse op te nemen. Ruby ondersteunt weliswaar geen meervoudige overerving, maar biedt mixin als alternatief om dat te bereiken.

hier is een voorbeeld dat uitlegt hoe meervoudige overerving wordt bereikt met mixin.

module A    # you create a module
    def a1  # lets have a method 'a1' in it
    end
    def a2  # Another method 'a2'
    end
end
module B    # let's say we have another module
    def b1  # A method 'b1'
    end
    def b2  #another method b2
    end
end
class Sample    # we create a class 'Sample'
    include A   # including module 'A' in the class 'Sample' (mixin)
    include B   # including module B as well
    def S1      #class 'Sample' contains a method 's1'
    end
end
samp = Sample.new    # creating an instance object 'samp'
# we can access methods from module A and B in our class(power of mixin)
samp.a1     # accessing method 'a1' from module A
samp.a2     # accessing method 'a2' from module A
samp.b1     # accessing method 'b1' from module B
samp.b2     # accessing method 'a2' from module B
samp.s1     # accessing method 's1' inside the class Sample

Antwoord 14

Ik heb zojuist een python-mixin gebruikt om unit-tests voor python-milters te implementeren. Normaal gesproken praat een milter met een MTA, wat het testen van eenheden moeilijk maakt. De testmixin negeert methoden die met de MTA praten en creëert in plaats daarvan een gesimuleerde omgeving die wordt aangedreven door testcases.

Dus je neemt een ongewijzigde milter-applicatie, zoals spfmilter, en mixin TestBase, zoals deze:

class TestMilter(TestBase,spfmilter.spfMilter):
  def __init__(self):
    TestBase.__init__(self)
    spfmilter.config = spfmilter.Config()
    spfmilter.config.access_file = 'test/access.db'
    spfmilter.spfMilter.__init__(self)

Gebruik vervolgens TestMilter in de testgevallen voor de milter-toepassing:

def testPass(self):
  milter = TestMilter()
  rc = milter.connect('mail.example.com',ip='192.0.2.1')
  self.assertEqual(rc,Milter.CONTINUE)
  rc = milter.feedMsg('test1',sender='[email protected]')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

http:/ /pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup


Antwoord 15

Ik las dat je een c#-achtergrond hebt. Een goed startpunt zou dus een mixin-implementatie voor .NET kunnen zijn.

Misschien wil je het codeplex-project bekijken op http://remix.codeplex.com/

Bekijk de link naar het lang.net Symposium voor een overzicht. Er komt nog meer documentatie op de codeplex-pagina.

groeten
Stefan

Other episodes