การใช้งาน Class กับโปรแกรมเชิงวัตถุ OOP ในภาษา Dart เบื้องต้น

เขียนเมื่อ 4 ปีก่อน โดย Ninenik Narkdee
การใช้งาน class โปรแกรมเชิงวัตถุ oop ในภาษา dart dart constructors

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

ดูแล้ว 9,407 ครั้ง




ในเนื้อหาในตอนต่อไปนี้ เราจะมาดูเกี่ยวกับการใช้งาน class เบื้องต้นในภาษา Dart
ตั้งแต่การกำหนด class การใช้งานงานตัวแปรใน class ที่เรีรยกว่า states หรือ property
การใช้งานฟังก์ชั่นการทำงานใน class ที่เรียกว่า method รวมถึงการใช้งานและการกำหนด
constructor ของ class เป็นต้น
 
 
สามารถทดสอบการเขียนโปรแกรมผ่านเว็บไซต์ DartPad 
 
 

การกำหนด Class

    เนื่องจากภาษา dart เป็นรูปแบบภาษาโปรแกรมเชิงวัตถุ (OOP) ทุกสิ่งใน dart ล้วนเป็น object และทุกๆ object ล้วนถูกสร้างมาจาก class
โดย class เปรียยสมือนพิมพ์เขียวหนึ่งๆ ที่สามารถนำไปสร้างเป็น object ได้หลายๆ ตัว  ยกตัวอย่างเช่น เราต้องการสร้างพิมพ์เขียวหุ่นยนต์
ขึ้นมา (เรากำลังจะสร้าง class)  และให้หุ่นยนต์ที่เราจะสร้างนั้น อาจจะมี property ต่างๆ เช่น ชื่อหรือหมายเลข ใช้พลังงานจากอะไร เป็นต้น
รวมไปถึงหุ่นยนต์นี้มีฟังก์ชั่นการทำงานหรือการกระทำอะไรที่สามารถทำได้ เช่น สามารถเดินได้ พูดได้ บินได้ นั่งได้ เต้นได้ เหล่านี้ ก็จะเป็นฟังก์ชั่น
การทำงาน หรือใน class ก็จะเรียกฟังก์ชั่นว่า method 
    มาเริ่มสร้าง class หุ่นยนต์ตามความเข้าใจเบื้องต้นกัน
 
void main () {

}

// การสร้าง class
class Robot{
  // state หรือ property ของ class หรือก็คือตัวแปร
  // สำหรับกำหนดคุณลักษณะ ของ class นั้นๆ
  String codeName;
  double height;
  bool walkable;
  bool talkable;
  
  // ฟังก์ชั่นการทำงาน หรือ method ที่จะบอกว่า หุ่นยนต์นั้น
  // ทำอะไรได้บ้าง
  void walking(){ // เดินได้
    print("Walking...");
  }
  void talking(){ // พูดคุยได้
    print("Talking...");
  }
   
}
 
    จะเห็นว่าในการสร้าง class เราเพียงกำหนด class keyword ด้านหน้า แล้วตามด้วยชื่อ class แล้วเปิดปิดด้วยเครื่องหมาย { } ภายในก็จะเป็นการกำหนด
ตัวแปรต่างๆ เป็น property และกำหนดฟังก์ชั่น เป็น method โดยทั้งสองส่วนล้วนเป็นเนื้อหาที่เราได้ทำความเข้าใจมาแล้ว ทบทวนได้ที่
    ตัวแปร Variable ในภาษา Dart http://niik.in/939
    Function ในภาษา Dart  http://niik.in/941
 
    ตัวอย่างโค้ดข้างต้น เรากำหนด class ชื่อ Robot ประกอบด้วย property ที่ชื่อ codeName, Height, walkable และ talkable  และมี 2 method คือ 
walking() และ talking()  นี้คือพิมพ์เขียวของ Robot ที่เราสร้างขึ้น ต่อไป เราต้องการนำพิมพ์เขียวนี้ไปสร้างเป็น หุ่นยนต์ 2 ตัว โดยสามารถทำได้ดังนี้
 
void main () {

  var humanoidA = Robot(); // สร้าง Robot object
  print(humanoidA.runtimeType); // Robot
  
  var humanoidB = Robot();  // สร้าง Robot object
  print(humanoidB.runtimeType); // Robot  
  
}
 
    เราสร้างตัวแปร humanoidA และ humanoidB เป็นตัวแปรอ้างอิง หรือที่เรียกว่า reference variable ให้มีค่าเท่ากับ instance of Robot object
ซึ่่งรูปแบบที่เราคุ้นเคยคือ 
    var humanioidA = new Robot(); 
 
    แต่ในภาษา dart เราไม่ระบุ "new" keyword ก็ได้ จึงได้เป็น
    var humanoidA = Robot(); 
 
    การเรียกใช้ Robot() เป็นการสร้าง Robot object ขึ้นมา ตัวแปร humanoidA จึงมีค่าเท่ากับ instance object ของ Robot ดังนั้น เมื่อเราทดสอบ
แสดงประเภทของตัวแปร โดยใช้คำสั่ง runtimeType เราก็จะได้ว่า humanoidA และ humanoidB ล้วนเป็น Robot หนึ่งๆ นั่นเอง
 
 
 

การใช้งานตัวแปรและฟังก์ชั่นใน class

    หลังจากที่เราทำการสร้าง instance object ขึ้นมาและเก็บไว้ในตัวแปร humanoidA และ humannoidB ข้างต้นแล้ว เราก็สามารถเรียกใช้งาน 
ตัวแปรและฟังก์ชั่นที่อยู่ใน object นั้นๆ ได้ โดยเราจะเรียกว่า instance variable และ instance method ตามลำดับ
 
void main () {

  var humanoidA = Robot();
  // การใช้งาน instance variable
  // การกำหนดค่า หรือเรียกว่า default setter
  humanoidA.codeName = 'ZA-05';
  humanoidA.height = 200;
  humanoidA.walkable = true;
  humanoidA.talkable = true;
  // การอ่านค่า หรือเรียกว่า default getter  
  print(humanoidA.codeName); // output: ZA-05  
  
  // การเรียกใช้งาน instance method   
  humanoidA.walking();
  humanoidA.talking();
  
  var humanoidB = Robot();
  // การใช้งาน instance variable
  // การกำหนดค่า หรือเรียกว่า default setter  
  humanoidB.codeName = 'ZB-03';
  humanoidB.height = 180;
  humanoidB.walkable = true;
  humanoidB.talkable = false;
  // การอ่านค่า หรือเรียกว่า default getter  
  print(humanoidB.codeName); // output: ZB-03
  
  // การเรียกใช้งาน instance method   
  humanoidB.walking();
}
 
    โค้ดตัวอย่างข้างต้น เราทำการเรียกใช้งาน ตัวแปรภายใน object ที่สร้างมาจาก class เราเรียกว่า instance variable โดยทดสอบทำการ
กำหนดค่าให้กับตัวแปรนั้น หรือที่เรียกว่าการกำหนด default setter  และทดสอบอ่านค่าโดยแสดงข้อมูลค่าของตัวแปร codeName หรือเรียกว่า
การใช้งาน default getter  นอกจากนั้น เรายังทดสอบเรียกใช้งาน instance method หรือฟังก์ชั่นใน class
 
 
 

การใช้งาน Constructors

    เราสามารถสร้าง object โดยใช้ constructor เพื่อกำหนดค่าให้กับ property ของ object ผ่านการกำหนด parameters constructor ได้  ก่อนลง
รายละเอียด เรากลับมาดูที่ class Robot ของเราก่อน
 
class Robot{
  String codeName;
  double height;
  bool walkable;
  bool talkable;
  
  // หาก class นั้นไม่ได้กำหนด constructor
  // จะมี default constructor เป็นชื่อเดียวกับ ClassName
  Robot(); // เรียกว่า default construtor 
  
  void walking(){ // เดินได้
    print("Walking...");
  }
  void talking(){ // พูดคุยได้
    print("Talking...");
  }
   
}

 

Default Constructor

    จะเห็นว่า หากเรากำหนด class โดยไม่มีการกำหนด constructor  ตัว class นั้นๆ จะมี default constructor เป็นชื่อเดียวกับ class อย่างโค้ดตัวอย่างข้างต้น
Robot() เป็น default constructor ที่ไม่มีการทำงานใดๆ ไม่มีการกำหนด parameter ดังนั้น เราจึงไม่จำเป็นต้องกำหนดค่านี้ ก็ได้ แต่สมมติว่า เราต้องการให้
ทำคำสั่งใดๆ ทันทีที่ทำการสร้าง object เราสามารถกำหนด default constructor โดยมีส่วนของ body เพื่อทำคำสั่งที่ต้องการได้ ตัวอย่างเช่น
 
void main () {
  var humanoidA = Robot(); // สร้าง Robot object
  humanoidA.codeName = 'ZA-05';
  humanoidA.height = 200;
  print(humanoidA.codeName); 
  humanoidA.walking();
  humanoidA.talking();
  
  var humanoidB = Robot(); // สร้าง Robot object
  humanoidB.codeName = 'ZB-03';
  humanoidB.height = 180;
  print(humanoidB.codeName); 
  humanoidB.walking();
}


class Robot{
  String codeName;
  double height;
  bool walkable;
  bool talkable;

  // default constructor
  Robot(){
    print("Default constructor runtime");
  }
  
  void walking(){ // เดินได้
    print("Walking...");
  }
  void talking(){ // พูดคุยได้
    print("Talking...");
  }
   
}
 
    ผลลัพธ์ที่ได้เมื่อรันคำสั่ง
 
Default constructor runtime
ZA-05
Walking...
Talking...
Default constructor runtime
ZB-03
Walking...
 
    จะเห็นว่า default constructor จะทำงานทุกครั้ง ทันทีที่มีการสร้าง object หรือมี instance object เกิดขึ้น 
 
 

Parameter Constructor

    หากเราต้องการสร้าง object พร้อมกับกำหนด parameter ให้สามารถที่จะส่งค่าไปใช้งานใน object นั้น สามารถทำได้ดังนี้
สมมติเราส่งค่า codeName กับ height เข้าไป จะได้เป็น
 
  // parameter constructor
  Robot(String codeName, double height){
    this.codeName = codeName;
    this.height = height;
  }
 
    หรือเขียนในรูปแบบดังนี้แทนก็ได้
 
  // parameter constructor
  Robot(this.codeName, this.height){
    // คำสั่งอื่นๆ เพิ่มเติม ถ้ามี
  }
 
    หรือกรณีต้องการกำหนดค่าอย่างเดียว ก็สามารถไม่กำหนดในส่วนของ body ให้กับ constructor ก็ได้ จะได้เป็น
 
  // parameter constructor
  Robot(this.codeName, this.height);
 
    รูปแบบการใช้งาน parameter constructor ข้างต้น เป็นการกำหนดค่าให้กับตัวแปร ในขั้นตอนการสร้าง object ผ่าน parameter ดังนั้น รูปแบบ
การเรียกใช้งาน ก็จะต้องปรับใหม่ โดยต้องทำการส่งค่า argument ไปด้วย ดังนี้
 
void main () {
  var humanoidA = Robot('ZA-05', 200); // สร้าง Robot object
  // ตัวแปร codeName และ height ถูกกำหนดค่าไปแล้วในขั้นตอนการสร้าง object  
  print(humanoidA.codeName);  // output: ZA-05
  humanoidA.walking();
  humanoidA.talking();
  
  var humanoidB = Robot('ZA-05', 180); // สร้าง Robot object
  // ตัวแปร codeName และ height ถูกกำหนดค่าไปแล้วในขั้นตอนการสร้าง object
  print(humanoidB.codeName);   // output: ZA-05
  humanoidB.walking();
}
 
    ในภาษา Dart เรายังมีวิธีการสร้าง object โดยสามารถเจาะจงความจำเพาะ ของ object นั้น โดยการใช้งาน named constructor โดยจะมีรูปแบบ
การกำหนด named constructor คือ ClassName.identifier โดย identifier คือคำจำเพราะ หรือคำที่ต้องการระบุแยกย่อยให้ชัดเจนในการสร้าง object นั้นๆ

 

Named Constructor

    สมมติเราต้องการสร้าง named constructor สำหรับสร้าง Robot object รุ่นเริ่มต้น ที่มี codeName ชื่อ "Demo-00" และ height เท่ากับ 150 เราสามารถ
กำหนด named constructor ใน Robto class ได้เป็นดังนี้
 
void main () {
  var humanoidA = Robot('ZA-05', 200); // สร้าง Robot object
  var humanoidB = Robot('ZA-05', 180); // สร้าง Robot object
  
  // สร้าง Robot object จาก named constructor
  var humanoidC = Robot.origin();
  print(humanoidC.codeName); // output: Demo-00
  
}

class Robot{
  String codeName;
  double height;
  bool walkable;
  bool talkable;

  // parameter constructor
  Robot(this.codeName, this.height);
  
  // named constuctor
  Robot.origin(){
    codeName = "Demo-00";
    height = 150;
  }
  
  void walking(){ // เดินได้
    print("Walking...");
  }
  void talking(){ // พูดคุยได้
    print("Talking...");
  }
   
}
 
    จะเห็นว่า origin เป็น identifier ที่เราต้องการกำหนดเจาะจง เป็นค่าอะไรก็ได้ ตามต้องการ สมมติ เราสร้างรุ่นพิเศษ ขึ้นมาใช้ชื่อว่า extra และมีการ
ใช้งาน parameter ร่วมด้วย เป็นดังนี้
 
    // named constuctor with parameter
  Robot.extra(this.codeName, this.height, this.talkable);
 
    เวลาเรียกใช้งาน ก็จะได้เป็น
 
  // สร้าง Robot object จาก named constructor และใช้งาน parameter
  var humanoidD = Robot.extra('EX-01', 300, true);
  if(humanoidD.talkable){
    humanoidD.talking(); // output: Talking...
  }
 
    เราสามารถกำหนด named constructor เท่าไหร่ก็ได้ ตามต้องการ ในขณะที่ parameter constructor จะสามารถกำหนดได้แค่ครั้งเดียวเท่านั้น
    เราสามารถกำหนดทั้ง parameter constructor และ named constructor พร้อมกันได้
 
 

Redirecting constructor

    ในกรณีที่เราต้องการส่งต่อบางค่า ไปใช้งานใน constructor หลัก เราสามารถทำการ redirect ค่านั้นโดยการกำหนดรูปแบบ constructor เป็น
redirecting constructor ดูตัวอย่างโค้ดดานล่างประกอบ 
 
  // Redirecting constructors
  Robot.smart(String codeName):this(codeName, 150);
 
    เรากำหนด named constructor ที่ชื่อ Robot.smart() ได้รับ parameter ที่เป็น codeName ค่าเดียว จากนั้นเรากำหนด : (colon) แล้วเรียกใช้งาน
constructor หลัก หรือก็คือ Robot(this.codeName, this.height) โดยส่งต่อ codeName ใน parameter แรก และฟิกค่า height เท่ากับ 150 ใน 
parameter ตัวที่สอง ดังนั้น this(codeName, 150) จึงหมายถึงการเรียกใช้งาน constructor หลักนั่นเอง ดูตัวอย่างโค้ดเต็มประกอบ
 
void main () {
  var humanoidA = Robot('ZA-05', 200); // สร้าง Robot object
  var humanoidB = Robot('ZA-05', 180); // สร้าง Robot object
  
  // สร้าง Robot object จาก named constructor
  var humanoidC = Robot.origin();
  print(humanoidC.codeName); // output: Demo-00
  
  // สร้าง Robot object จาก named constructor และใช้งาน parameter
  var humanoidD = Robot.extra('EX-01', 300, true);
  if(humanoidD.talkable){
    humanoidD.talking(); // output: Talking...
  }
  
  // สร้าง Robot object จาก redirecting constructor
  var humanoidE = Robot.smart('SM-01');
  print(humanoidE.codeName); // output: SM-01
  print(humanoidE.height); // output: 150
}

class Robot{
  String codeName;
  double height;
  bool walkable;
  bool talkable;

  // parameter constructor
  Robot(this.codeName, this.height);
  
  // named constuctor
  Robot.origin(){
    codeName = "Demo-00";
    height = 150;
  }
  
    // named constuctor with parameter
  Robot.extra(this.codeName, this.height, this.talkable);
  
  // Redirecting constructors
  Robot.smart(String codeName):this(codeName, 150);
  
  void walking(){ // เดินได้
    print("Walking...");
  }
  void talking(){ // พูดคุยได้
    print("Talking...");
  }
   
}
 
    หวังว่าเนื้อหาเกี่ยวกับการใช้งาน class ในภาษา Dart เบื้องต้น จะเป็นแนวทางสำหรับทบทวน ทำความเข้าใจ และนำไปประยุกต์ใช้งาน
ต่อไป สำหรับการใช้งาน class ยังมีส่วนที่เกี่ยวข้องต่างๆ อีก  จะได้นำเสนอในลำดับต่อๆ ไป


   เพิ่มเติมเนื้อหา ครั้งที่ 1 วันที่ 21-11-2019


Factory constructor

    ในภาษา Dart ยังรอบรับการใช้งาน factory constructor ซึ่งสามารถจะ return ค่ากลับมาเป็น subtype หรือ null ได้  สามารถกำหนด
และใช้งาน factory constructor โดยการใช้งาน "factory" keyword  
    ทำความเข้าใจคำว่า subtype ดังนี้
 
void main() {
  var a = A(); // สร้าง object
  print(a.runtimeType); // output: A
  var b = B();
  print(b.runtimeType); // output: B
}
class A{
  // default constructor
  A();
}
class B extends A{}
class C extends A{}
    จากตัวอย่างข้างต้น เมื่อเราสร้าง object จาก class A เราก็จะได้ type เป็น A  และถ้าเราสร้าง object จาก class B เราก็จะได้ type
เป็น B  เนื่้องจาก class B สืบทอดมาจาก class A อีกที ดังนั้น type B จึงเป็น subtype ของ type A  เช่นเดียวกันกับ type C ก็เป้น
subtype ของ A
    กลับมาที่นิยามของ factory constructor ซึ่งบอกว่า สามารถ return ค่าเป็น subtype หรือ null ได้ นั่นก็แสดงว่า เมื่อเราทำการ
สร้าง object จาก class A ก็สามารถ ที่จะได้ค่าเป็น type B หรือ type C หรือ null ได้ เมื่อมีการใช้งาน factory contructor
    ตัวอย่าง factory constructor ที่ return ค่าเป็น subtype B 
 
void main() {
  var a = A(); // สร้าง object
  print(a.runtimeType); // output: A  
  
  //  จะได้ b เป็น instance ของ subtype เท่ากับ B
  var b = A.name1(); // สร้าง object
  print(b.runtimeType); // output: B
}
class A{
  // default constructor
  A();
  
  // factory constructor
  factory A.name1(){
    return B();
  }
}
class B extends A{}
class C extends A{}
 
   เพื่อให้เห็นภาพชัดเจนขึ้น เรามาดู Shape class ที่สามารถสร้าง object แล้วคืนค่า เป็น subtype ตามชนิดประเภท type ที่ต้องการได้
 
void main() {
  var shape1 = Shape(); // สร้าง object
  print(shape1.runtimeType); // output: Shape  
  
  //  จะได้ shape2 เป็น instance ของ subtype เท่ากับ Circle
  var shape2 = Shape.fromTypeName("circle"); // สร้าง object
  print(shape2.runtimeType); // output: Circle
  
  //  จะได้ shape3 เป็น instance ของ subtype เท่ากับ Square
  var shape3 = Shape.fromTypeName("square"); // สร้าง object
  print(shape3.runtimeType); // output: Square
  
  //  จะได้ shape4 มีค่าเป็น null 
  var shape4 = Shape.fromTypeName("triangle"); // สร้าง object
  print(shape4.runtimeType); 
  // output: I don't recognize triangle
  // output: null  
}

class Shape {
  Shape(); // default constructor

  // factory constructor  ไม่สามารถใช้ this ในนี้ได้
  factory Shape.fromTypeName(String typeName) {
    if (typeName == 'square') return Square();
    if (typeName == 'circle') return Circle();
    
    print('I don\'t recognize $typeName');
    return null;
  }
}
class Square extends Shape {}
class Circle extends Shape {}
    จากโค้ด ทั้ง Square และ Circle ล้วนเป็น subtype ของ Shape เนื่องจากมีการสืบทอดจากมาก Shape class  และเมื่อเรามีการใช้งาน
factory constructor ที่ให้สามารถกำหนด type ที่ต้องการใช้งาน ได้ และคืนค่าเป็น type ที่ระบุ  หรือคืนค่าเป็น null หาก ค่าที่ระบุไม่ตรง
กับที่ได้กำหนดไว้ 
    เราไม่สามารถ return type ที่ไม่เป็น subtype ของ Shape ได้ สมมติเช่น เรามี Triangle class ดังนี้
 
class Shape {
  Shape(); // default constructor

  // factory constructor  ไม่สามารถใช้ this ในนี้ได้
  factory Shape.fromTypeName(String typeName) {
    if (typeName == 'square') return Square();
    if (typeName == 'circle') return Circle();
 //   if (typeName == 'triangle') return Triangle(); // error
    
    print('I don\'t recognize $typeName');
    return null;
  }
}
class Square extends Shape {}
class Circle extends Shape {}
class Triangle{}
 
    เราอาจกล่าวได้ว่า factory constructor มักใช้ในกรณีที่ไม่ต้องการสร้าง instance object จาก class นั้นๆ แต่อาจจะต้องการใช้งาน
subtype เพิ่มสร้าง instance object จาก class ลูกอีกที เป็นต้น
 
 
 

Const constructor

    ในกรณีเรามีการใช้งาน object ที่จะไม่มีการเปลี่ยนแปลงใดๆ เกิดขึ้น  เราสามารถกำหนดให้ object นั้นๆ เป็น constant หรือค่าที่ไม่
เปลี่ยนแปลง โดยใช้งาน const constructor พร้อมกับกำหนด ตัวแปร instance variable เป็น final ดังตัวอย่างการใช้งานต่อไปนี้
 
void main() {
  // ทดสอบแสดงค่า static variable
  print(ImmutablePoint.origin);
  // output:  Instance of 'ImmutablePoint'
  
  // สร้าง object ที่ไม่สามารถแก้ไขค่าได้
  var a = ImmutablePoint(100,200);
  print(a.x); // output: 100
  
  // error ไม่สามารถแก้ไขค่าได้
  // a.y = 500; 
}
// class จุดพักัดที่ไม่สามารถเปลี่ยนแปลงได้
class ImmutablePoint {
  // const constructor
  const ImmutablePoint(this.x, this.y);

  // ระบุ final ให้กับ instance variable
  final int x;
  final int y;

  // ใช้งาน static variable
  static const ImmutablePoint origin = ImmutablePoint(0, 0);
  // รูปแบบของบรรทัดด้านบนคือ 
  // [static variable] [แบบค่าคงที่่ const] [ชนิดข้อมูล ImmutablePoint] 
  // [ชื่อตัวแปร origin] = [การสร้าง object ด้วยคำสั่ง ImmutablePoint(0, 0)]
}


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



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









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









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





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







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