ในเนื้อหาตอนที่แล้ว เราได้ทำความรู้จักการสืบทอดของ class โดยใช้งาน
extends keyword การสืบทอดหรือที่เรียกว่า inheritance จะเป็นลักษณะ
ที่ให้ความสนใจไปที่การใช้งานร่วมกันระหว่าง class ทีเป็น parent class กับ
child class หรือเข้าใจอย่างง่ายก็เหมือน class ทั้งสอง class ที่มีความเกี่ยวเนื่อง
สัมพันธ์กัน เช่น child class เรียกใช้ property และ method ของ parent class
ผ่าน super keyword หรือแม้แต่ สามารถทำการ override ค่า property และ method
ของ parent class ได้ ตามที่ได้กล่าวไปแล้วในตอนที่ผ่านมา
ทบทวนเนื้อหาเกี่ยวกับการสืบทอด หรือ inheritance class ได้ที่ http://niik.in/944
สามารถทดสอบการเขียนโปรแกรมผ่านเว็บไซต์ DartPad
การใช้งาน Interface
ก่อนอื่นต้องให้เข้าใจก่อนว่า ในภาษา Dart จะไม่มี keyword ที่ชื่อ interface โดย interface เปรียยเหมือนการกำหนดหน้า
ตาหรือรูปแบบของ class ที่เราต้องการ หรือก็คือการกำหนดชื่อ property หรือ method รวมถึงประเภทข้อมูลของ property และ
method นั้นๆ เพื่อนำไปใช้งานอีกที
ในภาษา Dart จะมองว่าทุกๆ class เป็น interface สามารถนำไปใช้งานได้ โดยใช้ implements keyword ซึ่งการที่เราจะเลือกว่า class
ใด เหมาะที่จะมาใช้งานก็จะขึ้นกับความคล้ายคลึงในรูปแบบการใช้งาน ตัวอย่างเช่น
class Rectangle{ double width; double height; double area(){ // พื้นที่ return width * height; } double perimeter(){ // ความยาวเส้นรอบ return (width * 2) + (height * 2); } }
Rectangle class ข้างต้น เป็น class ของสี่เหลี่ยม ที่มี property ความกว้าง ความสูง และมี method ในการหาพื้น และ หรือความยาว
เส้นขอบของสี่เหลี่ยม สมมติเราต้องการสร้าง Circle class ที่มี method สำหรับหาพื้นที่ และมีมี method สำหรับหาความยาวเส้นรอบวง
เราก็จะพอมองออกว่า เราสามารถใช้ area() และ perimeter() method มาใช้งานใน Circle class ที่เราจะสร้างได้ สมมติ เราลองใช้วิธี
การสืบทอด โดยใช้ extends keyword เป็นดังนี้
class Circle extends Rectangle{ double radius; double pi = 3.14; @override double area(){ return pi * (radius * radius); } @override double perimeter(){ return 2 * pi * radius; } }
จะเห็นว่าเราสามารถทำการ extends Rectangle class เพื่อให้สามารถทำการ override method ที่เราต้องการจาก parent class ได้
แต่ถ้ามองดีๆ เราจะพบว่า Circle class ไม่ได้ต้องใช้งานอะไรจาก parent class มากนักนอกจาก interface เฉพาะ method area() และ
perimeter() ดังนั้นในส่วนนี้ การใช้งาน extends จึงไม่ใช้วิธีการที่เหมาะสม กรณีเรามอง Rectangle class เป็น interface เราควรใช้งาน
implements keyword แทน ดังนี้
class Circle implements Rectangle{ double radius; double pi = 3.14; // ต้องทำการกำหนด property และ method ของ class ที่ implements double width; double height; double area(){ return pi * (radius * radius); } double perimeter(){ return 2 * pi * radius; } }
การที่ Circle class ทำการ implements Rectangle class ข้างต้น เป็นการที่ Circle ทำการใช้งาน interface ของ Rectangle โดยไม่มีการ
สืบทอดเกิดขึ้น Circle ต้องทำการ กำหนด property และ method ให้เหมือนกับ Rectangle โดยจะใช้งานหรือไม่ก็ตาม ซึ่ง property และ
method ของ Circle จะไม่สัมพันธ์กับของใน Rectangle และไม่ใช่การ override เหมือนกรณีการใช้งาน extends
ดูตัวอย่างการใช้เพิ่มเติมตามโค้ดด้านล่าง
// class Rectangle (สี่เหลี่ยม) class Rectangle{ double width; double height; double area(){ // พื้นที่ return width * height; } double perimeter(){ // ความยาวเส้นรอบ return (width * 2) + (height * 2); } } // class Cube (ลูกบาศก์) class Cube{ double width; double height; double length; double volume(){ // หาปริมาตร return width * height * length; } } // class Circle (วงกลม) class Circle implements Rectangle{ double radius; double pi = 3.14; // ต้องทำการกำหนด property ของ Rectangle class ที่ implements double width; double height; double area(){ // method ของ Rectangle class ที่ implements return pi * (radius * radius); } double perimeter(){ // method ของ Rectangle class ที่ implements return 2 * pi * radius; } } // class Cylinder (ทรงกระบอก) class Cylinder implements Circle, Cube{ // ต้องทำการกำหนด property ของ Circle และ Cube class ที่ implements double radius; double pi = 3.14; double width; double height; double length; double area(){ // method ของ Circle class ที่ implements return pi * (radius * radius); } double perimeter(){ // method ของ Circle class ที่ implements return 2 * pi * radius; } double volume(){ // method ของ Cube class ที่ implements return area() * length; } }
จะเห็นว่าเราสามารถทำการ implements class เท่าไหร่ก็ได้ ต่างจากการ extends ที่สามารถสืบทอดได้เพียง class เดียว
จากโค้ด Cylinder class ใช้การ implements Circle และ Cube class ซึ่งถ้าเราสังเกตจะเห็นว่า การใช้งาน interface จาก class ปกติทั่วไป
หาก class นั้นมีความซับซ้อน เช่น มี property และ / หรือ method จำนวนมากๆ ก็จะทำให้เราต้องทำการกำหนด property และ method
เพิ่มขึ้นตามไปด้วย ทั้งที่บางค่า อาจจะไม่จำเป็นในการใช้งาน จึงมีรูปแบบ class หนึ่ง ที่เหมาะสำหรับใช้เป้น interface นั่นก็คือ abstract class
การใช้งาน Abstract Class
Abstract class มีประโยชน์มากในการนำมาใช้งานเป้น interface เพื่อแก้ปัญหา ที่เราเจอข้างต้น ที่เมื่อหากเราใช้งาน interface จาก class ทั่วไป
แล้วต้องกำหนด property และ method จำนวนมากๆ ทั้งๆ ที่บาง method หรือ property ไม่ได้จำเป็นสำหรับนำมาใช้งานในการสร้าง class ใหม่
abstract class คือ class ที่เราสามารถกำหนด property และ method สำหรับวางโครงหรือเป็นหน้าตา interface ที่เราจะนำไปใช้งานต่อได้ง่าย
โดยทั่วไปแล้ว abstract class จะมี abstract method ด้วยเสมอ การกำหนด abstract class จะใช้ abstract keyword ไว้ด้านหน้าของรูปแบบการ
กำหนด class ปกติทั่วไป ดังนี้
// abstract class รูปร่าง abstract class Shape{ double width; double height; // abstract method void area(); void perimeter(); } // abstract class รูปทรง abstract class Form{ double length; // abstract method void volume(); } // class Rectangle (สี่เหลี่ยม) class Rectangle implements Shape{ double width; double height; double area(){ // พื้นที่ return width * height; } double perimeter(){ // ความยาวเส้นรอบ return (width * 2) + (height * 2); } } // class Cylinder (ทรงกระบอก) class Cylinder implements Shape, Form{ double radius; double pi = 3.14; // ต้องทำการกำหนด property และ method ของ class ที่ implements double width; double height; double length; double area(){ // method ของ Shape class ที่ implements return pi * (radius * radius); } double perimeter(){ // method ของ Shape class ที่ implements return 2 * pi * radius; } double volume(){ // method ของ Form class ที่ implements return area() * length; } }
จากโค้ด เรามีการกำหนด abstract class ชื่อ Shape และ Form สำหรับนำไป implements ใช้งานในการสร้าง Rectangle และ Cylinder class
การใช้งาน abstract class ทำให้เราสามารถควบคุมโครงสร้างของ class ที่เราจะสร้างได้อย่างเหมาะสมตามต้องการ ได้ดีกว่าการใช้งาน interface
จาก class ปกติทั่วไป
สิ่งที่เราต้องรู้เกี่ยวกับ abstract class คือ abstract class ไม่สามารถนำไปสร้าง object ได้
void main () { // error เราไม่สามาถสร้าง object จาก abstract class ได้ // var shape = Shape(); // เราสามารถสร้าง object จาก class ที่ implements abstract class ได้ปกติ var regtangle = Rectangle(); print(regtangle); // output: Instance of 'Rectangle' }
การกำหนด abstract method จะกำหนดได้เฉพาะใน abstract class เท่านั้น โดยรูปแบบของ abstract method จะมีเฉพาะชื่อ method
และปิดด้วยเครื่องหมาย (;) เสมอ ตัวอย่างเช่น
abstract class Shape{ double width; double height; // abstract method void area(); void perimeter(); // เราสามารถกำหนด normal method ใน abstract class ได้ // แต่โดยทั่วไปแล้ว จะไม่กำหนด และหากกำหนด ต้องทำการ implements method นั้นๆ ด้วย void nomalMethod(){ } }
ตัวอย่างการกำหนด abstract method ใน class ปกติ ไม่สามารถทำได้
// class Rectangle (สี่เหลี่ยม) class Rectangle implements Shape{ // abstract method ไม่สามารถกำหนด ใน class ที่ใช่ abstract class ได้ // void volume(); // error }
abstract class อาจจะมีเฉพาะ method หรือ มีเฉพาะ property หรือ มีทั้งสองก็ได้
ตัวอย่าง abstract class ที่มีเฉพาะ method
// abstract class รูปร่าง abstract class Shape{ // abstract method void area(); void perimeter(); }
หวังว่าเนื้อหาเกี่ยวกับ interface และ abstract class จะช่วยให้เข้าใจในการใช้งานเพิ่มขึ้น และเป็นแนวทางในการ
ทำความเข้าใจในเนื้อหาอื่นๆ ต่อไป