Câu trả lời này nhằm giải thích các mixin với các ví dụ :
khép kín : ngắn gọn, không cần biết bất kỳ thư viện nào để hiểu ví dụ.
trong Python , không phải trong các ngôn ngữ khác.
Có thể hiểu rằng có các ví dụ từ các ngôn ngữ khác như Ruby vì thuật ngữ này phổ biến hơn nhiều trong các ngôn ngữ đó, nhưng đây là một chủ đề Python .
Nó cũng sẽ xem xét câu hỏi gây tranh cãi:
Là thừa kế cần thiết hay không để đặc trưng cho một mixin?
Định nghĩa
Tôi vẫn chưa thấy một trích dẫn từ một nguồn "có thẩm quyền" nói rõ một mixin trong Python là gì.
Tôi đã thấy 2 định nghĩa có thể có của một mixin (nếu chúng được coi là khác với các khái niệm tương tự khác như các lớp cơ sở trừu tượng) và mọi người không hoàn toàn đồng ý về cái nào là đúng.
Sự đồng thuận có thể khác nhau giữa các ngôn ngữ khác nhau.
Định nghĩa 1: không thừa kế nhiều
Một mixin là một lớp sao cho một số phương thức của lớp sử dụng một phương thức không được định nghĩa trong lớp.
Do đó, lớp không có nghĩa là được khởi tạo, mà là phục vụ như một lớp cơ sở. Nếu không, cá thể sẽ có các phương thức không thể được gọi mà không đưa ra một ngoại lệ.
Một ràng buộc mà một số nguồn thêm vào là lớp có thể không chứa dữ liệu, chỉ có các phương thức, nhưng tôi không hiểu tại sao điều này lại cần thiết. Tuy nhiên, trong thực tế, nhiều mixin hữu ích không có bất kỳ dữ liệu nào và các lớp cơ sở không có dữ liệu sẽ đơn giản hơn để sử dụng.
Một ví dụ kinh điển là việc triển khai tất cả các toán tử so sánh chỉ từ <=
và ==
:
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
Ví dụ cụ thể này có thể đã đạt được thông qua functools.total_ordering()
trang trí, nhưng trò chơi ở đây là phát minh lại bánh xe:
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)
Định nghĩa 2: đa thừa kế
Mixin là một mẫu thiết kế trong đó một số phương thức của lớp cơ sở sử dụng một phương thức mà nó không định nghĩa và phương thức đó có nghĩa là được thực hiện bởi một lớp cơ sở khác , không phải do dẫn xuất như trong Định nghĩa 1.
Thuật ngữ lớp mixin dùng để chỉ các lớp cơ sở được dự định sử dụng trong mẫu thiết kế đó (TODO những lớp sử dụng phương thức này hay các lớp thực hiện nó?)
Thật không dễ để quyết định xem một lớp nhất định có phải là một mixin hay không: phương thức có thể được thực hiện trên lớp dẫn xuất, trong trường hợp đó chúng ta quay lại Định nghĩa 1. Bạn phải xem xét ý định của tác giả.
Mẫu này rất thú vị vì có thể kết hợp lại các chức năng với các lựa chọn khác nhau của các lớp cơ sở:
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
Sự xuất hiện của Python có thẩm quyền
Tại tài liệu chính thức cho các bộ sưu tập.abc tài liệu sử dụng rõ ràng thuật ngữ Phương thức Mixin .
Nó nói rằng nếu một lớp:
- thực hiện
__next__
- kế thừa từ một lớp duy nhất
Iterator
sau đó lớp học được một __iter__
phương thức mixin miễn phí.
Do đó, ít nhất là về điểm này của tài liệu, mixin không yêu cầu nhiều kế thừa và phù hợp với Định nghĩa 1.
Tất nhiên, tài liệu này có thể trái ngược nhau ở những điểm khác nhau và các thư viện Python quan trọng khác có thể đang sử dụng định nghĩa khác trong tài liệu của họ.
Trang này cũng sử dụng thuật ngữ Set mixin
, trong đó gợi ý rõ ràng rằng các lớp thích Set
và Iterator
có thể được gọi là các lớp Mixin.
Trong các ngôn ngữ khác
Ruby: Rõ ràng không yêu cầu nhiều kế thừa cho mixin, như được đề cập trong các sách tham khảo chính như Lập trình Ruby và Ngôn ngữ lập trình Ruby
C ++: Một phương thức không được triển khai là một phương thức ảo thuần túy.
Định nghĩa 1 trùng với định nghĩa của một lớp trừu tượng (một lớp có một phương thức ảo thuần túy). Lớp học đó không thể được khởi tạo.
Định nghĩa 2 là có thể với thừa kế ảo: Nhiều kế thừa từ hai lớp dẫn xuất