เนื้อหาต่อไปนี้ เราจะอยู่ในโหมดของ OOP ในภาษา Dart
ต่อจากตอนที่แล้ว ที่พูดถึงเกี่ยวกับการใช้งาน Class การสร้าง
Object และการใช้งาน Constructor
ในตอนที่แล้ว ได้มีการพูดถึงการใช้งาน default getter และ default setter
ซึ่งก็คือการเรียกใช้ค่าตัวแปร และการกำหนดค่าตัวแปร ของ class object ไปบ้างเล็กน้อย
สามารถทบทวนได้ที่บทความ http://niik.in/942
สามารถทดสอบการเขียนโปรแกรมผ่านเว็บไซต์ DartPad
การใช้งาน Getter และ Setter
Getter และ Setter เป็นวิธีที่ใช้ในการอ่านและเขียนค่าข้อมูลให้กับตัวแปรใน object หรือที่เรียกว่า instance variable ซึ่งโดยปกติแล้ว
เมื่อมีการเรียกใช้ตัวแปร ไม่ว่าจะเป็นการอ่านค่าหรือกำหนดค่า ก็จะถือได้ว่ามีการใช้งาน default getter และ default setter ตามลำดับอยู่แล้ว
ซึ่งนอกจากวิธีการปกติโดยทั่วไป เรายังสามารถใช้งาน Getter และ Setter แบบกำหนดเองเพิ่มเติมได้ โดยใช้ get และ set keyword
ขอยก Robot class ของตอนที่แล้วมาประกอบการอธิบาย ตามตัวอย่าง ดังต่อไปนี้
void main () { var humanoidA = Robot('ZA-05'); // สร้าง Robot object // การกำหนดค่า หรือเรียกว่า default setter humanoidA.height = 200; // การอ่านค่า หรือเรียกว่า default getter print(humanoidA.height); // output: 200 } class Robot{ // instance variable // String codeName; double height; bool walkable; bool talkable; // parameter constructor Robot(this.codeName); // instance method // void walking(){ // เดินได้ print("Walking..."); } void talking(){ // พูดคุยได้ print("Talking..."); } }
จากโค้ดข้างต้น เรากำหนดค่าให้กับความสูง โดยเรียกใช้ default setter เพื่อกำหนดค่าให้กับ height ซึ่งเป็น object property หรือเรียกอีก
อย่างว่า instance variable จากนั้นเราทำการเรียกใช้ default getter เพื่อเรียกใช้ค่ามาแสดงโดยใช้คำสั่ง print() แล้วการใช้งาน getter และ
setter แบบกำหนดเองคืออะไร เริ่มตรงไหน
จะขอตัดบางส่วนของโค้ดด้านบนออก แล้วดูตัวอย่างพร้อมคำอธิบายด้านล่าง
void main () { var humanoidA = Robot('ZA-05',200); // สร้าง Robot object // การใช้งาน การกำหนดค่าด้วย custom setter // ตัวเลข 50 คือ percent parameter ที่ส่งเข้าไปคำนวณในฟังก์ชั่น // set weight(double percent) humanoidA.weight = 50; // หนัก 50% ของความสูง // การใช้งาน การอ่านค่าด้วย custom getter print(humanoidA.weight); // output: 100 } class Robot{ // instance variable // String codeName; double height; double calcWweight; // parameter constructor Robot(this.codeName, this.height); // กำหนด custom getter double get weight{ return calcWweight; } // กำหนด custom setter ให้น้ำหนัก ได้จากการคิด เปอร์เซ็นของความสูง void set weight(double percent){ calcWweight = (height * percent) / 100; } }
เราทำการเพิ่มตัวแปร calcWeight สำหรับเก็บค่า น้ำหนักที่ได้จากการคำนวณ โดยการกำหนดน้ำหนักให้กับหุ่นยนต์นั้น เราต้องการให้มีน้ำหนัก
ได้จากการคำนวณจากเปอร์เซ็นต์ของความสูง โดยให้ส่งค่า percent ที่ต้องการเข้ามา ในตอนเรียกใช้งาน จะเห็น่ว่าต่างจากการใช้งาน default
setter ที่เมื่อเรากำหนดค่าใดๆ เข้ามาแล้ว จะมีค่าเท่ากับค่าที่กำหนด แต่กรณีนี้ เราต้องการให้ค่าที่ส่งเข้ามา ถูกนำไปคำนวณก่อนแล้วจึงส่งค่ากลับ
ออกมาหรือก็คือรูปแบบการใช้งาน custom setter จากตัวอย่าง หุ่นยนต์มีความสูงที่ 200 และเราส่งค่า percent น้ำหนักที่ต้องการเท่ากับ 50
เปอร์เซ็นต์เข้ามา หรือก็คือต้องการให้คำนวณน้ำหนักของหุ่นยนต์เท่ากับ 50 เปอร์เซ็นต์ของความสูง ซื่งก็คือ 100
หลังจากกำหนดค่าโดยใช้ custom setter แล้ว เราก็ทำการเรียกใช้ค่า หรืออ่านค่าด้วย custom getter ซึ่งก็ได้จากการ return ค่าตัวแปร calcWeight
ที่ได้จากการคำนวณกลับออกมานั่นเอง โดยในการกำหนด getter จะไม่มีการใช้งาน parameter ใดๆ
เราสามารถใช้รูปแบบ fat arrow ในการกำหนด getter และ setter ได้ โดยสามารถปรับเป็นดังนี้
class Robot{ // instance variable // String codeName; double height; double calcWweight; // parameter constructor Robot(this.codeName, this.height); // กำหนด custom getter | custom setter double get weight => calcWweight; void set weight(double percent) => calcWweight = (height * percent) / 100; }
Private instance variable
ในภาษา Dart จะไม่มีการกำหนด public, protected และ private keyword ในการใช้งาน อย่างไรก็ตาม ใน Dart มีการใช้ (_) underscore
ในการกำหนดค่า private ที่ให้สามารถเรียกใช้ค่านั้นๆ ได้เฉพาะใน library ของตัวมันเองเท่านั้น ไม่สามารถเรียกใช้ค่าจาก library อื่นๆ ได้
ให้เข้าใจแบบนี้ว่า ทุกๆ app ในภาษา dart เรียกว่า libray อย่างโค้ดด้านบน ก็คือ library หนึ่ง สมมติเราสร้างอีกไฟล์ขึ้นมาชื่อ other.dart
และกำหนดโค้ดเป็นดังนี้
// ไฟล์ other.dart class RobotBase{ // กำหนด private instance variable String _height = "Two hundred"; void about(){ print("String value: $_height");// Output: Two hundred _height = "One hundred fifty"; print("String value: $_height");// Output: One hundred fifty } }
จากนั้นเราทำการ import library มาใช้งานในไฟล์ robot.dart และเรียกใช้งานดังนี้
// ไฟล์ robot.dart import 'other.dart'; void main () { var humanoidA = Robot('ZA-05',200); // สร้าง Robot object // เรียกใช้งาน aboutRobot method humanoidA.aboutRobot(); } class Robot extends RobotBase{ // instance variable // String codeName; double _height; // กำหนดเป็น private instance variable Robot(this.codeName, this._height); void aboutRobot(){ print("Double value: $_height"); // Output: 200 _height = 150; about(); // เรียกใช้ method ของ RobotBase class print("Double value: $_height"); // Output: 150 } }
สังเกตว่าไฟล์ other.dart และ robot.dart ก็คือ library คนละตัวกัน โดยไฟล์ robot.dart มีการเรียกใช้งาน other library โดยทำการ import
เข้ามาใช้งาน จากนั้น ทำการ extends หรือสืบทอด Robot class จาก RobotBase class ที่อยู่ในอีก library ทั้ง RobotBase และ Robot class
มีการกำหนด private instance variable ชื่อ _height เหมือนกัน แต่เป็นชนิดข้อมูลต่างกันคือเป็น String และ Double ตามลำดับ
เมื่อเราทดสอบ โดยการเรียกใช้งาน aboutRobot() method เพื่อแสดงค่าข้อมูลของตัวแปร _height ใน Robot library โดยใน aboutRobot()
method ก็ทำการเรียกใช้งาน about() method ที่อยู่ใน other library เพื่อแสดงค่าตัวแปร _hegiht ใน Other library ผลลัพธ์ที่ได้ เป็นดังนี้
// Double value: 200 // String value: Two hundred // String value: One hundred fifty // Double value: 150
จะเห็นว่า ตัวแปร _height ของแต่ละ library จะไม่สามารถเรียกใช้งาน หรือไม่มีผลในอีก library หากมีการกำหนดเป็น private สังเกตจากตัวอย่าง
ที่เมื่อเรากำหนดค่าตัวแปร _height = 150 ค่าตัวแปร จะเปลี่ยนแปลงเฉพาะใน library ตัวมันเองเท่านั้น ไม่มีผลกับ ค่าใน library อื่น
เนื่อหาเกี่ยวกับ getter และ setter และการทำความเข้าใจเกี่ยวกับ private instance variable เบื้องต้น จะเป็นแนวทางทำความเข้าใจส่วนอื่นๆ ต่อไป