Каква е разликата между миксин и наследяване?
Mixin срещу наследство
Отговори (9)
Миксинът обикновено се използва с множествено наследяване. Така че в този смисъл няма разлика.
Подробността е, че миксин рядко е полезен като самостоятелен обект.
Например, да кажем, че имате миксин с име ColorAndDimension, който добавя свойство цвят и ширина и височина.
Сега можете да добавите ColorAndDimension към, да речем, клас Shape, клас Sprite, клас Car и т.н. И всички те ще имат един и същ интерфейс (да кажем get/setColor, get/setHeight/Width и т.н.)
И така, в общия случай миксин Е наследяване. Но можете да спорите, че това е въпрос на ролята на класа в цялостния домейн дали миксинът е основен клас или просто миксин.
Редактиране - само за пояснение.
Да, миксин може да се счита, в днешния модерен жаргон, за интерфейс със свързано изпълнение. Това наистина е просто, старо, ежедневно множествено наследяване, използващо обикновен, стар, ежедневен клас. Това просто се случва да бъде специфично приложение на MI. Повечето езици не дават на mixin специален статус; това е просто клас, който е проектиран да бъде смесен, вместо да се използва самостоятелно.
Каква е разликата между миксин и наследяване?
Mix-in е основен клас, от който можете да наследите, за да осигурите допълнителна функционалност. Пример за псевдокод:
class Mixin:
def complex_method(self):
return complex_functionality(self)
Името "mix-in" показва, че е предназначено да бъде смесено с друг код. Като такъв, изводът е, че не бихте инстанцирали смесения клас сам. Следният обект няма данни и няма смисъл да се инстанцира, за да извика complex_method. (В такъв случай можете просто да дефинирате функция вместо клас.)
>>> obj = Mixin()
Често смесването се използва с други базови класове.
Следователно миксините са подмножество или специален случай на наследяване.
Предимствата на използването на смесване пред единичното наследяване са, че можете да напишете код за функционалността еднократно и след това да използвате същата функционалност в множество различни класове. Недостатъкът е, че може да се наложи да потърсите тази функционалност на други места, различни от мястото, където се използва, така че е добре да смекчите този недостатък, като я държите наблизо.
Аз лично открих смесване, необходимо за използване при единично наследяване, където тестваме модули на много подобен код, но тестовите случаи се инстанциират въз основа на тяхното наследяване на основен случай и единственият начин да запазим кода близо до ръка (и в същия модул), без да се забърквате с номерата на покритието, е да наследявате от обект и да наследявате дъщерните случаи както от универсалната база за тестови случаи, така и от персонализираната база, която се отнася само за тях.
Миксини в сравнение и контраст с абстрактни базови класове
И двата са форма на родителски клас, който не е предназначен да бъде инстанциран.
Миксин осигурява функционалност, но не може да я използва директно. Потребителят е предназначен да го използва чрез (под)клас.
Един абстрактен базов клас предоставя интерфейс, но без използваема функционалност. Потребителят е предназначен да създаде функционалността, извикана от интерфейса.
class Abstraction(metaclass=abc.ABCMeta):
@abc.abstractmethod
def complex_method(self):
return complex_functionality(self)
Тук сте възпрепятствани да създадете екземпляр на този обект, тъй като той изисква подклас за внедряване на функционалност с конкретен метод (въпреки че можете да получите достъп до функционалността от 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
В Python някои класове в модула abc
са примери за родителски класове, които осигуряват функционалност чрез наследяване и абстрактни интерфейси, които трябва да бъдат имплементирани от подкласа. Тези идеи не се изключват взаимно.
Резюме
Казано по-просто, смесването е просто базов клас, който не бихте инстанцирали сам и обикновено се използва като вторичен базов клас при множествено наследяване.
mix-in е специфичен, ограничен случай на (множествено) наследяване, използван за целите на изпълнението; някои езици (напр. Ruby) го поддържат, без да поддържат обобщено множествено наследяване.
Mixin е абстрактна концепция и всичко, което отговаря на нейните изисквания, може да се счита за mixin.
Ето едно определение от Уикипедия.
В обектно-ориентираните езици за програмиране миксинът е клас, който съдържа методи за използване от други класове, без да е необходимо да бъде родителският клас на тези други класове. Как тези други класове получават достъп до методите на mixin зависи от езика. Миксините понякога се описват като „включени“, а не като „наследени“.
Накратко, ключовата разлика от наследяването е, че смесванията НЕ трябва да имат връзка „е-а“, както при наследяването.
От гледна точка на внедряването можете да го мислите като интерфейс с реализации. Например, абстрактен клас в Java може да се разглежда като mixin, ако Java поддържа множествено наследяване.
„Миксинът е фрагмент от клас в смисъл, че е предназначен да бъде съставен с други класове или миксини.“ -ДДЖ
Mixin е клас или кодов фрагмент, който не е предназначен за самостоятелна употреба, но вместо това трябва да го използвате вътре в друг клас. Или да го съставите като членско поле/променлива, или като кодов сегмент. Имам най-голямо излагане на по-късно. Това е малко по-добро от копиране и поставяне на шаблонен код.
Ето една страхотна статия за DDJ, която представя темата.
Half-Life 2 / "Source" SDK е чудесен пример за C++ mixins. В тази среда макросите дефинират значителни блокове код, които могат да бъдат добавени, за да придадат на класа специфичен „вкус“ или функция.
Погледнете примера на уики източника: Създаване на логически обект. В примерния код макросът DECLARE_CLASS може да се счита за миксин. Изходният SDK използва широко миксини за стандартизиране на кода за достъп до данни и приписване на поведение на обекти.
Миксините се използват широко по начин, подобен на плъгини.
Те са еднакви, но в различен контекст всеки един от тях. Обикновено, когато говорим за наследяване, говорим за ЕДИНСТВЕНО наследяване, а mixin е конструкция, която позволява МНОЖЕСТВО наследяване.
Това е езикова конструкция, която е силно противоречива в света на ООП поради:
- Неяснотата, че трябва да се разреши
- Много от времето миксин класовете не работят сами по себе си и може да са в конфликт с други миксини
- Това може да доведе до проблем с наследяването на диамант, при който два супер класа могат да наследяват от един и същи клас
Но това настрана, това е мощна конструкция, която се използва в различни езици и рамки, някои примери са:
- Django
- Typescript
При множествено наследяване новият клас може да бъде съставен от множество суперкласове. Можете да извиквате само методи, дефинирани в някой от суперкласовете.
От друга страна, mixin е абстрактен подклас, който може да се използва за специализиране на поведението на различни родителски класове. Миксините могат да извикат метод (например sayHello(): String
), въпреки че не дефинират такъв метод.
mixin M {
name: String
defmethod greetings() { print sayHello() + " " + name}
}
Както виждате, можете да извикате sayHello()
, въпреки че не е дефинирано никъде. Ако добавите mixin M
към клас C
, C
трябва да предостави метода sayHello()
.
Мисля, че е важно да се отбележи, че mixin не предполага наследяване. Според wikipedia Mixin е:
В обектно-ориентираните езици за програмиране миксинът е клас, който съдържа методи за използване от други класове, без да е необходимо да бъде родителският клас на тези други класове. Как тези други класове получават достъп до методите на mixin зависи от езика. Миксините понякога се описват като „включени“, а не като „наследени“.
По-конкретно, в език като perl, mixins могат да се добавят с помощта на модула 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'));
}
Които могат да бъдат смесени към всеки модул, съдържащ един или повече метод(и) наведнъж:
package MrT
use Mixins qw(pity);
sub new {
return bless({}, shift);
}
sub _who_do_i_pity {
return 'da foo!'
}
Тогава във вашия MrT
модул може да се използва по следния начин:
use MrT;
MrT->new()->pity();
Знам, че примерът е абсурден, но разбира смисъла...
tl;dr
mixin и множественото наследяване имат една и съща форма. Но имат различна семантика: mixin има основните класове, осигуряващи изпълнението на функцията. За наследяване базовите класове предоставят интерфейс, а подкласът има имплементацията.
Но както и да е, композицията е за предпочитане пред mixin IMO