Mixin เทียบกับมรดก


คำตอบ:


69

โดยทั่วไปแล้ว mixin จะใช้กับการสืบทอดหลายรายการ ดังนั้นในแง่นั้น "ไม่มีความแตกต่าง"

รายละเอียดคือมิกซ์อินแทบไม่มีประโยชน์ในฐานะออบเจ็กต์แบบสแตนด์อโลน

ตัวอย่างเช่นสมมติว่าคุณมี mixin ชื่อ "ColorAndDimension" ซึ่งจะเพิ่มคุณสมบัติสีและความกว้างและความสูง

ตอนนี้คุณสามารถเพิ่ม ColorAndDimension ให้กับ a พูดคลาส Shape คลาส Sprite คลาส Car และอื่น ๆ และทั้งหมดนี้จะมีอินเทอร์เฟซเดียวกัน (พูดว่า get / setColor, get / setHeight / Width ฯลฯ )

ดังนั้นในกรณีทั่วไปการถ่ายทอดทางพันธุกรรมของมิกซ์อิน แต่คุณสามารถโต้แย้งได้ว่ามันเป็นเรื่องของบทบาทของคลาสในโดเมนโดยรวมว่ามิกซ์อินเป็นคลาส "หลัก" หรือเพียงแค่มิกซ์อิน


แก้ไข - เพียงเพื่อชี้แจง

ใช่มิกซ์อินถือได้ว่าเป็นอินเทอร์เฟซที่มีการใช้งานที่เกี่ยวข้อง จริงๆแล้วมันเป็นเพียงการถ่ายทอดทางพันธุกรรมแบบเก่า ๆ ในชีวิตประจำวันโดยใช้คลาสธรรมดา ๆ ในชีวิตประจำวัน มันเป็นเพียงแอปพลิเคชั่นเฉพาะของ MI ภาษาส่วนใหญ่ไม่ได้ให้สถานะพิเศษใด ๆ เป็นเพียงคลาสที่ออกแบบมาให้ "ผสมกัน" แทนที่จะใช้แบบสแตนด์อโลน


30

อะไรคือความแตกต่างระหว่าง Mixin และการถ่ายทอดทางพันธุกรรม?

ผสมในเป็นชั้นฐานคุณสามารถรับมรดกจากเพื่อให้การทำงานเพิ่มเติม ตัวอย่าง Pseudocode:

class Mixin:
    def complex_method(self):
        return complex_functionality(self)

ชื่อ "mix-in" แสดงว่ามีวัตถุประสงค์เพื่อผสมกับรหัสอื่น ๆ ดังนั้นการอนุมานก็คือคุณจะไม่สร้างอินสแตนซ์คลาสมิกซ์อินด้วยตัวมันเอง อ็อบเจ็กต์ต่อไปนี้ไม่มีข้อมูลและไม่มีเหตุผลที่จะสร้างอินสแตนซ์ให้เรียก complex_method (คุณสามารถกำหนดฟังก์ชันแทนคลาสได้เช่นกัน)

>>> obj = Mixin()

บ่อยครั้งที่การมิกซ์อินถูกใช้กับคลาสพื้นฐานอื่น ๆ

ดังนั้นมิกซ์อินจึงเป็นส่วนย่อยหรือกรณีพิเศษของการถ่ายทอดทางพันธุกรรม

ข้อดีของการใช้ mix-in over single inheritance คือคุณสามารถเขียนโค้ดสำหรับฟังก์ชันการทำงานได้ครั้งเดียวจากนั้นใช้ฟังก์ชันเดียวกันในคลาสต่างๆ ข้อเสียคือคุณอาจต้องมองหาฟังก์ชันการทำงานนั้นในที่อื่นนอกเหนือจากที่ใช้งานดังนั้นจึงเป็นการดีที่จะลดข้อเสียนั้นโดยการเก็บไว้ใกล้ ๆ

ฉันพบว่ามีการผสมผสานที่จำเป็นในการใช้กับการสืบทอดเดียวโดยที่เรากำลังทดสอบรหัสที่คล้ายกันจำนวนมาก แต่กรณีทดสอบนั้นได้รับการสร้างอินสแตนซ์ตามการสืบทอดของกรณีพื้นฐานและวิธีเดียวที่จะทำให้รหัสปิด มือ (และในโมดูลเดียวกัน) โดยไม่ต้องยุ่งกับหมายเลขความครอบคลุมคือการสืบทอดจากออบเจ็กต์และให้เคสลูกสืบทอดจากฐานกรณีทดสอบสากลและฐานแบบกำหนดเองที่ใช้กับพวกมันเท่านั้น

ส่วนผสมในการเปรียบเทียบและความคมชัดกับคลาสฐานนามธรรม

ทั้งสองเป็นรูปแบบของคลาสแม่ที่ไม่ได้ตั้งใจให้เป็นอินสแตนซ์

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โมดูลเป็นตัวอย่างของคลาสพาเรนต์ที่ทั้งสองมีฟังก์ชันการทำงานผ่านการสืบทอดและอินเทอร์เฟซนามธรรมที่คลาสย่อยต้องนำไปใช้ ความคิดเหล่านี้ไม่สามารถใช้ร่วมกันได้

สรุป

พูดง่ายๆว่าการมิกซ์อินเป็นเพียงคลาสพื้นฐานที่คุณจะไม่สร้างอินสแตนซ์ด้วยตัวมันเองและโดยทั่วไปจะใช้เป็นคลาสฐานรองในการสืบทอดหลาย ๆ


18

การผสมผสานเป็นกรณีที่เฉพาะเจาะจงและ จำกัด ของการสืบทอด (หลายรายการ) ที่ใช้เพื่อวัตถุประสงค์ในการนำไปใช้งาน บางภาษา (เช่น Ruby) รองรับโดยไม่รองรับการสืบทอดหลาย ๆ


7

Mixin เป็นแนวคิดเชิงนามธรรมและอะไรก็ตามที่ตรงตามความต้องการถือได้ว่าเป็น mixin

นี่คือคำจำกัดความจาก Wikipedia

ในภาษาโปรแกรมเชิงวัตถุมิกซ์อินคือคลาสที่มีเมธอดสำหรับใช้โดยคลาสอื่นโดยไม่จำเป็นต้องเป็นคลาสพาเรนต์ของคลาสอื่น ๆ คลาสอื่น ๆ เหล่านั้นเข้าถึงเมธอดของ mixin ได้อย่างไรนั้นขึ้นอยู่กับภาษา บางครั้งมีการอธิบายว่ามิกซ์อินเป็น "รวม" มากกว่า "สืบทอด"

ในระยะสั้นความแตกต่างที่สำคัญจากการถ่ายทอดทางพันธุกรรมคือมิกซ์อินไม่จำเป็นต้องมีความสัมพันธ์แบบ "is-a" เหมือนการถ่ายทอดทางพันธุกรรม

จากมุมมองการนำไปใช้งานคุณสามารถคิดว่ามันเป็นอินเทอร์เฟซสำหรับการใช้งาน ตัวอย่างเช่นคลาสนามธรรมใน Java อาจถือได้ว่าเป็นมิกซ์อินหาก Java รองรับการสืบทอดหลายรายการ


ฉันมีช่วงเวลาที่ยากที่จะเข้าใจประโยคที่เป็นตัวหนา ดูเหมือนว่า "ความแตกต่าง (ของ B?) จาก A คือ (B?) ต้องการบางอย่างใน A" คุณกำลังพูดถึงความแตกต่างหรือความเหมือน?
RayLuo

@RayLuo อ๊ะ ... ฉันพิมพ์ผิดไปบ้าง ขออภัยที่ทำให้คุณสับสน มิกซ์อินไม่จำเป็นต้องมีความสัมพันธ์แบบ "is-a"
Alex

3

"มิกซ์อินคือส่วนหนึ่งของคลาสในแง่ที่ตั้งใจจะแต่งกับคลาสอื่นหรือมิกซ์อิน" -DDJ

mixin เป็นส่วนของคลาสหรือโค้ดที่ไม่ได้มีไว้สำหรับการใช้งานแบบสแตนด์อโลน แต่คุณควรใช้มันในคลาสอื่นแทน ทั้งการเขียนเป็นเขตข้อมูลสมาชิก / ตัวแปรหรือเป็นส่วนรหัส ฉันมีความเสี่ยงมากที่สุดในภายหลัง ดีกว่าการคัดลอกโค้ดสำเร็จรูปเล็กน้อย

นี่เป็นบทความ DDJ ที่ดีที่แนะนำเรื่องนี้

Half-Life 2 / "Source" SDK เป็นตัวอย่างที่ดีของ C ++ mixins ในมาโครสภาพแวดล้อมนั้นจะกำหนดบล็อคโค้ดขนาดใหญ่ซึ่งสามารถเพิ่มเพื่อให้คลาสมี "รสชาติ" หรือคุณลักษณะเฉพาะ

ดูที่มาวิกิพีเดียเช่น: การเขียนตรรกะ Entity ในโค้ดตัวอย่างมาโคร DECLARE_CLASS ถือได้ว่าเป็นมิกซ์อิน ซอร์ส SDK ใช้มิกซ์อินอย่างกว้างขวางเพื่อสร้างมาตรฐานของโค้ดการเข้าถึงข้อมูลและกำหนดพฤติกรรมให้เอนทิตี


0

ด้วยการสืบทอดหลายชั้นคลาสใหม่อาจประกอบขึ้นจากซูเปอร์คลาสหลายคลาส คุณสามารถเรียกเฉพาะเมธอดที่กำหนดไว้ในซูเปอร์คลาส

ในทางกลับกัน mixin เป็นคลาสย่อยนามธรรมที่อาจใช้เพื่อสร้างความเชี่ยวชาญให้กับคลาสแม่ที่หลากหลาย Mixins อาจเรียกเมธอด (เช่นsayHello(): String) แม้ว่าจะไม่ได้กำหนดวิธีการดังกล่าวก็ตาม

mixin M {
    name: String
    defmethod greetings() { print sayHello() + " " + name}
}

อย่างที่คุณเห็นคุณสามารถโทรsayHello()ได้แม้ว่าจะไม่ได้กำหนดไว้ที่ใดก็ตาม ถ้าคุณเพิ่ม mixin MไปเรียนCที่Cควรให้sayHello()วิธีการ


1
ไม่แน่ใจเกี่ยวกับความถูกต้องของคำสั่งแรกของคุณ - ชั้นเรียนสามารถกำหนดวิธีการของตนเองได้
EugeneMi

0

ผมคิดว่ามันสำคัญที่จะต้องทราบว่าmixinไม่ได้หมายความถึงการถ่ายทอดทางพันธุกรรม ตามวิกิพีเดีย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();

ฉันรู้ว่ามันเป็นตัวอย่างที่ไร้สาระ แต่มันได้ประเด็น ...


0

tl; dr

mixin และ multi inheritance มีรูปแบบเดียวกัน แต่มีความหมายที่แตกต่างกัน: mixin มีคลาสพื้นฐานให้การใช้งานฟังก์ชัน สำหรับการสืบทอดคลาสพื้นฐานจะจัดเตรียมอินเตอร์เฟสและคลาสย่อยมีการนำไปใช้

แต่อย่างไรก็ตามควรใช้องค์ประกอบมากกว่า mixin IMO


0

Mixins ถูกนำมาใช้อย่างมากมายในลักษณะที่คล้ายกัน

เหมือนกัน แต่ในบริบทที่แตกต่างกัน โดยปกติเมื่อเราพูดถึงการถ่ายทอดทางพันธุกรรมเรากำลังพูดถึงการถ่ายทอดทางพันธุกรรมแบบเดี่ยวและมิกซ์อินเป็นโครงสร้างที่อนุญาตให้มีการสืบทอดหลาย ๆ

นี่คือโครงสร้างภาษาที่มีการถกเถียงกันอย่างมากในโลก OOP เนื่องจาก:

  • ความคลุมเครือที่จะต้องได้รับการแก้ไข
  • โดยมากแล้วคลาส "มิกซ์อิน" จะไม่ทำงานด้วยตัวเองและอาจขัดแย้งกับมิกซ์อินอื่น
  • อาจส่งผลให้เกิด "ปัญหาการสืบทอดเพชร" โดยที่ซุปเปอร์คลาสสองคลาสสามารถสืบทอดจากคลาสเดียวกันได้

แต่นอกเหนือจากนั้นเป็นโครงสร้างที่ทรงพลังซึ่งใช้ในภาษาและกรอบงานต่าง ๆ ตัวอย่างบางส่วน ได้แก่ :

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.