Odpowiedzi:
Mixin jest zwykle używany z dziedziczeniem wielokrotnym. Więc w tym sensie „nie ma różnicy”.
Szczegół jest taki, że mixin rzadko jest przydatny jako samodzielny obiekt.
Na przykład, załóżmy, że masz mixin o nazwie „ColorAndDimension”, który dodaje właściwość koloru oraz szerokość i wysokość.
Teraz możesz dodać ColorAndDimension do, powiedzmy, klasy Shape, klasy Sprite, klasy Car itp. I wszystkie będą miały ten sam interfejs (powiedzmy get / setColor, get / setHeight / Width itp.)
Tak więc, w ogólnym przypadku dziedziczenie mieszane JEST. Ale można argumentować, że jest to kwestia roli klasy w ogólnej domenie, czy mieszanka jest klasą „podstawową”, czy po prostu mieszanką.
Edycja - tylko dla wyjaśnienia.
Tak, mixin można uznać, w dzisiejszym nowoczesnym języku, za interfejs z powiązaną implementacją. To naprawdę jest zwykłe, stare, codzienne wielokrotne dziedziczenie przy użyciu zwykłej, starej, codziennej klasy. Tak się składa, że jest to specyficzne zastosowanie MI. Większość języków nie nadaje mieszance żadnego specjalnego statusu; jest to po prostu klasa, która została zaprojektowana jako „wmieszana”, a nie używana samodzielnie.
Jaka jest różnica między mieszanką a dziedziczeniem?
Mix-in jest klasą bazową można dziedziczyć, aby zapewnić dodatkową funkcjonalność. Przykład pseudokodu:
class Mixin:
def complex_method(self):
return complex_functionality(self)
Nazwa „mix-in” wskazuje, że jest przeznaczone do mieszania z innym kodem. W związku z tym wniosek jest taki, że nie utworzyłbyś wystąpienia samej klasy mieszanej. Poniższy obiekt nie zawiera danych i nie ma sensu tworzyć jego wystąpienia w celu wywołania metody complex_method. (W takim przypadku możesz równie dobrze zdefiniować funkcję zamiast klasy).
>>> obj = Mixin()
Często mieszanie jest używane z innymi klasami bazowymi.
W związku z tym mieszanki są podzbiorem lub szczególnym przypadkiem dziedziczenia.
Zaletą korzystania z mieszania w porównaniu z dziedziczeniem pojedynczym jest to, że można jednorazowo napisać kod funkcji, a następnie użyć tej samej funkcji w wielu różnych klasach. Wadą jest to, że możesz potrzebować poszukać tej funkcji w innych miejscach niż tam, gdzie jest używana, więc dobrze jest złagodzić tę wadę, trzymając ją blisko siebie.
Osobiście znalazłem mieszankę konieczną do użycia w przypadku pojedynczego dziedziczenia, w której usuwamy wiele podobnego kodu, ale przypadki testowe są tworzone na podstawie ich dziedziczenia przypadku podstawowego i jedynego sposobu, aby kod był blisko hand (iw tym samym module), bez mieszania się z numerami pokrycia, ma dziedziczyć po obiekcie i sprawić, by przypadki potomne dziedziczyły zarówno z uniwersalnej bazy przypadków testowych, jak i niestandardowej bazy, która ma zastosowanie tylko do nich.
Obie są formą klasy nadrzędnej, której instancja nie jest przeznaczona.
Mixin zapewnia funkcjonalność, ale nie jest w stanie bezpośrednio z niego korzystać. Użytkownik powinien używać go za pośrednictwem (pod) klasy.
Abstrakcyjna klasa bazowa zapewnia interfejs, ale bez użytecznej funkcjonalności. Celem użytkownika jest stworzenie funkcji wywoływanej przez interfejs.
class Abstraction(metaclass=abc.ABCMeta):
@abc.abstractmethod
def complex_method(self):
return complex_functionality(self)
Tutaj nie można utworzyć wystąpienia tego obiektu, ponieważ wymaga on podklasy do zaimplementowania funkcjonalności za pomocą konkretnej metody (chociaż można uzyskać dostęp do funkcji z poziomu super()
):
>>> obj = Abstraction()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Abstraction with
abstract methods complex_method
W Pythonie niektóre klasy w abc
module są przykładami klas nadrzędnych, które zapewniają funkcjonalność poprzez dziedziczenie i abstrakcyjne interfejsy, które muszą być implementowane przez podklasę. Te pomysły nie wykluczają się wzajemnie.
Mówiąc prościej, mieszanka jest po prostu klasą bazową, której nie utworzyłbyś samodzielnie i zwykle jest używana jako dodatkowa klasa bazowa w dziedziczeniu wielokrotnym.
mieszanie to specyficzny, ograniczony przypadek (wielokrotnego) dziedziczenia używany do celów wdrożeniowych; niektóre języki (np. Ruby) obsługują go bez obsługi uogólnionego dziedziczenia wielokrotnego.
Mixin jest pojęciem abstrakcyjnym i wszystko, co spełnia jego wymagania, można uznać za mixin.
Oto definicja z Wikipedii.
W zorientowanych obiektowo językach programowania, mixin jest klasą zawierającą metody do wykorzystania przez inne klasy, bez konieczności bycia klasą nadrzędną tych innych klas. Sposób, w jaki inne klasy uzyskują dostęp do metod miksera, zależy od języka. Składniki są czasami opisywane jako „uwzględnione”, a nie „dziedziczone”.
Krótko mówiąc, kluczową różnicą w stosunku do dziedziczenia jest to, że mieszanki NIE muszą mieć relacji „jest-a”, tak jak w przypadku dziedziczenia.
Z punktu widzenia implementacji można to traktować jako interfejs z implementacjami. Na przykład abstrakcyjna klasa w Javie może być traktowana jako mieszana, jeśli Java obsługuje wielokrotne dziedziczenie.
„Mixin to fragment klasy w tym sensie, że ma być komponowany z innymi klasami lub mixinami”. -DDJ
Mixin to klasa lub fragment kodu, który nie jest przeznaczony do samodzielnego użytku, ale zamiast tego powinien być używany wewnątrz innej klasy. Albo komponując go jako pole / zmienną składową, albo jako segment kodu. Najbardziej narażam się na późniejsze. To trochę lepsze niż kopiowanie i wklejanie kodu standardowego.
Oto świetny artykuł DDJ, który wprowadza ten temat.
Zestaw SDK Half-Life 2 / „Source” jest doskonałym przykładem miksów C ++. W tym środowisku makra definiują duże bloki kodu, które można dodawać, aby nadać klasie określony „smak” lub funkcję.
Spójrz na przykład źródła wiki: Tworzenie jednostki logicznej . W przykładowym kodzie makro DECLARE_CLASS można uznać za element mieszany. Source SDK używa w szerokim zakresie mixins do standaryzacji kodu dostępu do danych i przypisywania zachowań jednostkom.
W przypadku dziedziczenia wielokrotnego nowa klasa może składać się z wielu nadklas. Możesz wywoływać tylko metody zdefiniowane w dowolnej z nadklas.
Z drugiej strony, mixin to abstrakcyjna podklasa, której można użyć do specjalizacji w zachowaniu różnych klas nadrzędnych. Miksery mogą wywołać metodę (na przykład sayHello(): String
), nawet jeśli nie definiują takiej metody.
mixin M {
name: String
defmethod greetings() { print sayHello() + " " + name}
}
Jak widzisz, możesz dzwonić, sayHello()
nawet jeśli nigdzie nie jest to zdefiniowane. Jeśli dodasz mixin M
do klasy C
, C
powinieneś podać sayHello()
metodę.
Myślę, że ważne jest, aby zauważyć, że mixin nie oznacza dziedziczenia . Według Wikipedii Mixin to:
W zorientowanych obiektowo językach programowania, mixin jest klasą zawierającą metody do wykorzystania przez inne klasy, bez konieczności bycia klasą nadrzędną tych innych klas. Sposób, w jaki inne klasy uzyskują dostęp do metod miksera, zależy od języka. Składniki są czasami opisywane jako „uwzględnione”, a nie „dziedziczone”.
W szczególności w języku takim jak Perl, mixin można dodawać za pomocą modułu Exporter:
package Mixins;
use Exporter qw(import);
our @EXPORT_OK = qw(pity);
# assumes it will be mixed-in to a class with a _who_do_i_pity method
sub pity {
my ($self) = @_;
printf("I pity %s\n", $self->_who_do_i_pity('da foo'));
}
Które można dodać do dowolnego modułu zawierającego jedną lub więcej metod naraz:
package MrT
use Mixins qw(pity);
sub new {
return bless({}, shift);
}
sub _who_do_i_pity {
return 'da foo!'
}
Następnie w swoim MrT
module można wykorzystać w ten sposób:
use MrT;
MrT->new()->pity();
Wiem, że to absurdalny przykład, ale trafia w sedno ...
tl; dr
mixin i wielokrotne dziedziczenie mają tę samą postać. Ale mają inną semantykę: mixin ma podstawowe klasy zapewniające implementację funkcji. W przypadku dziedziczenia klasy podstawowe zapewniają interfejs, a podklasa ma implementację.
W każdym razie kompozycja jest preferowana w stosunku do mieszanej IMO