การกำหนด และใช้งาน Mixins ในโปรแกรมภาษา Dart เบื้องต้น

14 November 2019 By Ninenik Narkdee
dart oop ใน ภาษา dart mixins

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ dart oop ใน ภาษา dart mixins



เนื้อหาตอนต่อไปนี้ เราจะมาดูเกี่ยวกับการใช้งาน Mixins
ตั้งแต่ความรู้จักกับ mixins  วิธีการใช้งาน และประโยชน์ของการ
ใช้งาน mixins เป็นต้น ตามลำดับ
 
สามารถทดสอบการเขียนโปรแกรมผ่านเว็บไซต์ DartPad 
 
 

Mixins คืออะไร

    Mixins เป็นวิธีที่ใช้ในการเรียกใช้ class ซ้ำหรือนำมาใช้งานอีกครั้ง 
ใน class ที่มีการสืบทอด หลายลำดับขั้น  โดย class ที่จะนำมาใช้งานเป็น mixins นั้น
ต้องเป็น class ที่ไม่ได้สืบทอดหรือ extends มาจาก class อื่น นอกจาก Object class
รวมถึงเป็น class ที่ไม่มีการกำหนด contructor parameter และไม่มีการเรียกใช้คำสั่ง super() ด้วย
    โดยทั่วไปแล้ว Mixins จะใช้สำหรับกำหนด การทำงานหรือฟังก์ชั่น ให้สามารถใช้งานร่วมกับ
class ที่มีกาาสืบทอด อยู่คนละดำดับขั้นกัน  หรือใช้สำหรับกรณีที่ไม่สามารถกำหนดการทำงานเพิ่มเติม
ให้กับ parent class ของ class นั้นๆ ได้
 
    ดูตัวอย่าง class ที่ทำหน้าที่เป็น mixins 
 
// class นักบิน
class Piloted {
  // instance variable [property หรือ state ของ class]
  int astronauts = 1; // นักบินอวกาศ 
  
  // instance method [ฟังก์ชั่นการทำงานของ class]
  void describeCrew() { // อธิบายจำนวนลูกเรือ 
    print('Number of astronauts: $astronauts');
  }
}

// class ยานอวกาศ
class Spacecraft{}

// class PilotedCraft ยานอวกาศที่มีนักบิน สืบทอดมาจาก Spacecraft 
// และใช้งาน mixins Piloted
class PilotedCraft extends Spacecraft with Piloted {
  // PilotedCraft มี astronauts property และ describeCrew() method
  //  ไว้ใช้งาน จากการใช้งาน mixins Piloted
}
 
 
 

การกำหนด และใช้งาน Mixins

    ในการใช้งาน Mixins จะใช้ keyword "with" ต่อจาก class ที่มีการสืบทอด แล้วตามด้วย ชื่อ mixins ที่ต้องการใช้งาน
ซึ่งสามารถกำหนดได้มากกว่า 1 mixins และไม่จำกัด
    ยกตัวอย่าง โครงสร้าง Animal class แยกเป็น Mammal (สัตว์เลี้ยงลูกด้วยนม) และ Bird (สัตวปีก)
แล้วก็แยกย่อย ในแต่ละประเภทอีก ดังนี้
 
Animal
    - Mammal
        - Dolphin
        - Bat
        - Cat
    - Bird
        - Dove
        - Duck
 
    Mixins class ก็จะเหมือน class ของการกระทำหรือพฤติกรรม ที่สามารถนำมาใช้งานซ้ำได้ เช่น ปลาโลมา อยู่ในส่วนของ
สัตว์เลี้ยงลูกด้วยนมสามารถว่ายน้ำได้ เช่นเดียวกับเป็ดที่อยู่ในกลุ่มสัตว์ปีก  ค้างคาวสามารถบินได้เหมือนสัตว์ปีก  ค้างคาว แมว
นกพิราบ และเป็ด สามารถเดินได้ เหล่านี้เป็นต้น พฤติกรรมอย่าง การว่ายน้ำได้ เดินได้ และบินได้ เป็นส่วนที่ mixins ใช้ประโยชน์
ในการนำไปใช้ซ้ำใน class   ดูตัวอย่างประกอบ
 
void main () {

//   สร้าง object 
  var cat = Cat();
  var dove = Dove();
   
  // A cat can walk
  cat.walk();
// ผลลัพธ์  
// I am walking
   
  // a dove can walk and fly
  dove.walk();
  dove.fly();
// ผลลัพธ์  
// I am walking  
// I am flying    
  
}

// โครงสร้าง class ที่มีการสืบทอดกันในหลายลำดับขั้น
class Animal{}
class Mammal extends Animal{}
class Bird extends Animal{}
 
// Mixins class ที่สามารถนำไปใช้ร่วมกัน หรือเรียกใช้ซ้ำได้
class Walker{
  void walk(){
    print("I am walking");
  }
}
class Swimmer{
  void swim(){
    print("i am swimming");
  }
}
class Flyer{
  void fly(){
    print("i am flying");    
  }
}
 
// class ที่มีการสืบทอด อยู่คนละโครงสร้างลำดับขั้น
// มีกการใช้งาน mixins class เรียกใช้ผ่าน with keyword
// เพื่อใช้งานความสามารถร่วมกัน หรือใช้ซ้ำได้
class Dilphin extends Mammal with Swimmer{}
class Bat extends Mammal with Walker, Flyer{}
class Cat extends Mammal with Walker{}
class Dove extends Bird with Walker, Flyer{}
class Duck extends Bird with Walker, Swimmer, Flyer{}
 
    สังเกตจะเห็นว่า Mixins จะเหมือนการเพิ่มความสามารถให้กับ class คล้ายกับ การสืบทอดทั่วไป แต่เนื่องจากว่า ในภาษา Dart จะ
สามารถสืบทอดได้เพียง Parent เดียวเท่านั้น   ดังนั้น Mixins จึงเหมือนเป้นตัวช่วยให้สามารถเรียกใช้คำสั่งหรือการทำงานเพิ่มเติมได้
และเหมาะกับการนำไปใช้ใน class ที่มีการสืบทอด อยู่คนละโครงสร้างลำดับขั้น  
    อย่างตัวอย่างข้างต้น เช่น Cat อยู่ในลำดับขั้นของ Mammal และมีความสามารถในการเดิน ใช้งาน Walker Mixins เช่นเดียวกับ
Duck ที่ใช้งาน Walker Mixins เหมือนกัน  โดยที่ทั้ง Cat และ Duck อยู่คนละลำดับขั้นกัน แต่สามารถนำ Mixins มาใช้งานร่วมกันได้
 
    class ที่ใช้งานเป็น mixins ข้างต้น มีการสืบทอดมาจาก Object (base class ของทุกตัวในภาษา Dart สืบทอดมาจาก Object class)
ดังนั้น class ที่จะใช้เป็น mixins จะต้องไม่มีการสืบทอดมจาก class อื่น นอกจาก Object class  หรือก็คือ
 
    class Walker{}      มาจาก    class Walker extends Object{}
    class Swimmer{}  มาจาก    class Swimmer extends Object{}
    class Flyer{}         มาจาก    class Flyer extends Object{} 
    สมมติเรากำหนดให้ Flyer ทำการ extends มาจาก Bird  ตามตัวอย่างข้างล่าง
 
// Flyer class จะไม่สามารถใช้เป็น mixin ได้ ถ้ามีการ extends 
// จาก class อื่น ที่ไม่ใช่ Object class
class Flyer extends Bird{ // ไม่สามารถใช้เป็น mixin ได้ // เกิด error
  void fly(){
    print("i am flying");    
  }
}

// กรณีเหล่านี้จะเกิด error ไม่สามารถใช้งาน Flyer เป็น mixin ได้
class Bat extends Mammal with Walker, Flyer{}
class Dove extends Bird with Walker, Flyer{}
class Duck extends Bird with Walker, Swimmer, Flyer{}
    กรณีข้างต้น เราไม่สามารถใช้ Flyer ไปกำหนดเป็น mixins ได้
    การที่ mixins ไม่สามารถสืบทอดจาก class อืนที่ไม่ใช้ Object class ได้นั่น ทำให้ เราไม่สามารถเรียกใช้งาน method ที่อยู่ใน super class
ได้ ยกตัวอย่างด้านล่าง
 
// โครงสร้าง class ที่มีการสืบทอดกันในหลายลำดับขั้น
class Animal{
  void method(){
    print("Animal");
  }
}
class Bird extends Animal{
  void method(){
    print("Bird");
  }
}
class Walker{ // mixins
  void walk(){    
    print("I am walking");
  }
}
class Flyer{  // mixins error
  void fly(){
    super.method(); // error ไม่สามรถใช้งานได้
    print("i am flying");    
  }
}

// error 
// Flyer ไม่สามารถใช้งาน method() ที่อยู่ใน Bird class ได้
class Dove extends Bird with Walker, Flyer{}
    อย่างไรก็ตาม เราสามารถแก้ปัญหานี้ได้ด้วยการใช้งาน "mixin" keyword แทนคำว่า "class" keyword แล้วทำการกำหนดชื่อ class ที่ต้องการให้
mixins นั้นสามารถใช้งาน method ใน class นั้นๆ ได้ โดยระบุต่อจาก "on" keyword  จะได้เป็นดังนี้
 
void main () {

//   สร้าง object 
  var dove = Dove();

  // a dove can walk and fly
  dove.walk();
  dove.fly();
// ผลลัพธ์  
// I am walking จาก walker mixins
// Bird  จาก Bird class ที่ Dove class สืบทอดมา
// i am flying จาก flyer mixins
  
}

// โครงสร้าง class ที่มีการสืบทอดกันในหลายลำดับขั้น
class Animal{
  void method(){
    print("Animal");
  }
  void method2(){
    print("Animal 2");
  }  
}
class Bird extends Animal{
  void method(){
    print("Bird");
  }
}
mixin Walker{ // mixins
  void walk(){    
    print("I am walking");
  }
}
mixin Flyer on Bird{ // mixins
  void fly(){
    super.method(); // สามารถเรียกใช้งาน method ใน class ที่ระบุได้
    print("i am flying");    
  }
}

class Dove extends Bird with Walker, Flyer{}
    จะเห็นว่า Flyer mixins ในคำสั่ง fly() มีการใช้งาน super ซึ่งเป็นการเรียกใช้งาน parent class ที่มีการสืบทอดมา โดยระบุไปว่าใช้กับ
Bird class ด้วย "on" keyword ซึ่งเมื่อ Dove ทำการสืบทอดมาจาก Bird และเมื่อมีการใช้งานคำสั่ง fly() ด้วยรูปแบบ dove.fly()  
เมื่อคำสั่ง super.method() ถูกเรียกใช้งาน ก็จะเป็นการไปใช้คำส่ง method() ใน Bird class ที่เป็น parent นั่นเอง
    นอกจากเราจะสามารถใช้งาน method ของ Bird class ที่เป็น parent ได้แล้ว เรายังสามารถใช้งาน method ของ Animal class ที่
Bird class ได้ทำการสืบทอดมาอีกทีได้ นั่นคือ เราสามารถใช้คำสั่ง super.method1()  จะเห็น metthod1() เป็นคำสั่งใน Animal class
แต่ถูกสืบทอดส่งต่อมายัง Bird class ด้วย เราจึงสามารถเรียกใช้งานคำสั่งนี้ได้
    โดยสรุปก็คือ การใช้งาน "mixin" keyword จะเป็นการทำให้ mixins ทำหน้าที่คล้ายกับ class ปกติทั่วไป มากกว่าการใช้งาน "class"
keyword ในการกำหนดเป็น mixins
 
 
    ต่อไปเรามาดูกรณีการใช้งาน mixins หลายตัว และดูความสำคัญของลำดับการกำหนดการใช้งาน mixins ผ่าน "with" keyword โดย
ดูตัวอย่างโค้ดด้านล่างประกอบ
 
void main () {
  var c = C();
  // ถ้าลำดับ mixin เป็น a,b
  // จะใช้ method จาก ตัวหลังสุดกรณี มี method ชื่อเดียวกัน
  
  print(c.msg());
  // output: เป็น B ถ้าใช้ mixins เป็น with a,b
  // รูปแบบ class C extends P with a,b{}
  // output: เป็น A ถ้าใช้ mixins เป็น with b,a
  // รูปแบบ class C extends P with b,a{}  
}
mixin a{
  String msg() => "A";
}
mixin b{
  String msg() => "B";
}

class P{}
class C extends P with a,b{}
    จะเห็นว่า เมื่อมีการใช้งาน mixins ที่มี method เดียวกัน (msg() เป็น method ที่เขียนแบบ arrow syntax)  หากมีการเรียกใช้งาน method
จะใช้ method ที่อยู่ใน mixins ที่ระบุในตัวหลังสุดก่อนถ้ามี อย่างผลลัพธ์ของกรณีข้างต้น เมื่อใช้ mixins เป็น with a,b จะได้ว่า b เป็น mixin
ตัวหลังสุด ที่มี msg() method เมื่อถูกเรียกใช้งาน ค่าก็จะได้เป็น B  หากเราสลับตำแหน่งกันเป็น with b,a ก็จะได้ว่า mixin ตัวหลังสุดคือ a
ค่าที่ได้ ก็จะเป็น A เป็นต้น
    แต่ถ้า class C มีการกำหนด method msg() ด้วย ค่าที่ได้ ก็จะเป็นการใช้งานของ C class เช่น
 
class C extends P with a,b{
  String msg() => "C";  
}
    หากเรียกใช้งานด้วยคำสั่ง c.msg() ค่าที่ได้ก็จะเป็น C 
    ลำดับการใช้งาน method ใน class และ mixins ที่มีการ override จะเป็นไปดังนี้คือ
    
    C -> b -> a -> P
 
    จะใช้งาน msg() ใน C class หากมี msg() ใน C class  แต่ถ้า หากไม่มี ให้ไปดูที่ mixins ตัวสุดท้าย แล้ว ไล่กลับเข้ามา หรือก็คือ b และ a
class ตามลำดับ และมาจบที่ P class ที่ C class ได้ทำการสืบทอดมา
 
    
    หวังว่าเนื้อหาเกี่ยวกับ mixins จะเป็นแนวทางทำความเข้าใจ และทบทวน เพื่อนำไปใช้งานต่อๆ ไป


เพียงกด Like หรือ Share เป็นกำลังใจ ในการสร้างบทความใหม่ๆ น่ะครับ



อ่านต่อที่บทความ









เนื้อหาที่เกี่ยวข้อง



Tags:: dart mixins oop ใน ภาษา dart







URL สำหรับอ้างอิง











เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ