Mixin vs dziedziczenie

Odpowiedzi:

66

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.

Will Hartung
źródło
29

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.

Miksy w porównaniu i kontraście z abstrakcyjnymi klasami bazowymi

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 abcmodule 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.

Podsumowanie

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.

Aaron Hall
źródło
18

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.

Alex Martelli
źródło
7

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.

Alex
źródło
Trudno mi zrozumieć to odważne zdanie. Brzmi jak „różnica (B?) Od A polega na tym, że (B?) Potrzebuje czegoś takiego jak w A”. Czy mówisz o różnicy lub podobieństwie?
RayLuo
@RayLuo Ups ... Zrobiłem literówkę. Przepraszam, że cię zmylić. Mix-iny NIE muszą mieć związku "jest-a"
Alex
3

„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.

Karol Poganin
źródło
0

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 Mdo klasy C, Cpowinieneś podać sayHello()metodę.

jk_
źródło
1
nie jestem pewien co do poprawności twojego pierwszego stwierdzenia - klasy mogą definiować własne metody
EugeneMi
0

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 MrTmodule można wykorzystać w ten sposób:

use MrT;

MrT->new()->pity();

Wiem, że to absurdalny przykład, ale trafia w sedno ...

Lucas
źródło
0

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

del bao
źródło