openplanning

Phương thức trong Dart

Xem thêm các chuyên mục:

Hãy theo dõi chúng tôi trên Fanpage để nhận được thông báo mỗi khi có bài viết mới. Facebook

1- Phương thức là gì?

Trong ngôn ngữ lập trình Dart, phương thức là một khối mã (block of code) được định nghĩa bên trong một lớp và chỉ chạy khi được gọi. Các phương thức chia nhiệm vụ lớn thành các phần nhỏ và thực hiện hoạt động cụ thể của chương trình đó. Quá trình này làm tăng khả năng tái sử dụng mã và nâng cao cách tiếp cận mô-đun của chương trình.
Về cơ bản, phương thức được chia làm 3 loại:
  1. Phương thức thông thường (không tĩnh và không trừu tượng).
  2. Phương thức tĩnh (static method).
  3. Phương thức trừu tượng (abstract method).

2- Phương thức thông thường

Cú pháp định nghĩa một phương thức thông thường:

return_type method_name(arguments)    {  
     // statement(s)  
}
  • return_type: Kiểu dữ liệu trả về của phương thức, sử dụng từ khoá void như một kiểu trả về nếu phương thức không trả về gì cả.
  • method_name: Tên phương thức. Khác với các ngôn ngữ khác như Java, Dart không cho phép 2 phương thức cùng tên, kể cả khi chúng có các tham số khác nhau. Điều này là cần thiết để có thể chuyển đổi mã Dart sang Javascript.
  • arguments: Các tham số của phương thức.
Ví dụ: Lớp Cat và phương thức sayHello(..) của nó. Để gọi phương thức sayHello(..) bạn phải tạo một đối tượng Cat và gọi phương thức bằng cách sử dụng ký hiệu dấu chấm (dot notation).
method_ex1.dart

class Cat {
  void sayHello(String name) {
    print("Hello $name");
  }
}

void main() {
  Cat tom = new Cat(); // Create a Cat object.

  tom.sayHello("Jerry"); // Call the method through the object.
}
Output:

Hello Jerry
Một phương thức có thể chứa 0, 1 hoặc nhiều tham số, các tham số cách nhau bởi dấu phẩy.
method_ex2.dart

class Rectangle {
  int width;
  int height;
  // Constructor
  Rectangle(this.width, this.height) ;

  int getArea() {
    return width * height;
  }
  void changeWidthHeight(int newWidth, int newHeight)  {
      width = newWidth;
      height = newHeight;
  }
  void showMe()  {
     print('I am a rectangle, width: $width, height: $height');
  }
}

void main() {
   Rectangle rec = Rectangle(5, 10); // Create an object.
  
   rec.showMe();  // Call the method.
   var area = rec.getArea();  // Call the method.
   print('Area: $area');
  
   print(' --- Change width and height --- ');
   rec.changeWidthHeight(25, 15); // Set newWidth, newHeight

   rec.showMe(); // Call the method.  
   area = rec.getArea(); // Call the method.
   print('Area: $area');
}
Output:

I am a rectangle, width: 5, height: 10
Area: 50
--- Change width and height ---
I am a rectangle, width: 25, height: 15
Area: 375

3- Phương thức tĩnh

Dart sử dụng từ khoá static và cú pháp định nghĩa một phương thức thông thường để định nghĩa một phương thức tĩnh.
Cú pháp định nghĩa phương thức tĩnh:

static return_type method_name(arguments)    {  
     // statement(s)  
}
Các đặc điểm của phương thức tĩnh:
  • Phương thức tĩnh được gọi thông qua tên lớp và ký hiệu dấu chấm. Chẳng hạn MyUtility.sum(100, 50). Tên lớp và ký hiệu dấu chấm có thể được bỏ qua nếu gọi phương thức tĩnh trong nội bộ lớp đó.
  • Các thành viên không tĩnh của một lớp không thể xuất hiện trong phương thức tĩnh trừ khi chúng được truy cập thông qua đối tượng (Xem thêm ví dụ phía dưới).
method_static_ex1.dart

class MyUtility {
  static int sum(int a, int b)  {
    return a + b;
  }
  static int minus(int a, int b)  {
    return a - b;
  }
}

void main() {
   var result = MyUtility.sum(100, 50);
   print('Sum Result: $result');

   result = MyUtility.minus(100, 50);
   print('Minus Result: $result');
}
Output:

Sum Result: 150
Minus Result: 50
Tiếp theo, nhìn vào ví dụ dưới đây:
  • side1, side2side3 là các trường (field) không tĩnh của lớp Triangle, chúng không thể xuất hiện trong phương thức tĩnh.
  • Gọi phương tĩnh trong nội bộ lớp có thể không cần thông qua tên lớp và ký hiệu dấu chấm.
method_static_ex2.dart

class Triangle {
  late double side1;
  late double side2;
  late double side3;
  static const String DEFAULT_COLOR  = 'blue'; // Static field

  Triangle(double s1, double s2, double s3) {
    bool valid = isValidSides(s1, s2, s3); // Check if all sides are valid.
    if(!valid) {
      throw ArgumentError('Invalid Sides!'); // Throw an Error.
    }
     side1 = s1;
     side2 = s2;
     side3 = s3;
  }

  static bool isValidSides(double s1, double s2, double s3)  {
     if(s1 < 0 || s2 < 0 || s3 < 0)  {
       return false;
     }
     return s1 + s2 > s3 && s1 + s3 > s2 && s2 + s3 > s1;
  }

  bool isEquilateralTriangle() {
      return side1 == side2 && side2 == side3;
  }
}

void main() {
   bool valid = Triangle.isValidSides(6, 8, 10);
   print('Are sides 6, 8 and 10 valid to make a triangle? $valid');

   var triangle = Triangle(3.0, 4.0, 5.0);
  
   // Check if the triangle is equilateral triangle.
   var check = triangle.isEquilateralTriangle();
   print('Is Equilateral Triangle? $check');
}
Output:

Are sides 6, 8 and 10 valid to make a triangle? true
Is Equilateral Triangle? false

4- Phương thức trừu tượng

Trong ngôn ngữ Dart, phương thức trừu tượng là một phương thức không tĩnh và không có nội dung.

abstract return_type method_name(arguments);
Một lớp có ít nhất một phương thức trừu tượng phải được khai báo là trừu tượng. Một trong các lớp con của lớp trừu tượng sẽ ghi đè (override) các phương thức trừu tượng và viết nội dung cho nó.
Ví dụ: Lớp Person dưới đây phải được khai báo là lớp trừu tượng vì nó có ít nhất một phương thức trừu tượng.
method_abstract_ex1.dart

abstract class Person {
  void sayHello(); // An abstract method.
}

class EnglishPerson extends Person {
  void sayHello() {
    print("Hello");
  }
}
class RussianPerson extends Person {
   void sayHello() {
      print("Привет");
   }
}

void main() {
    Person enPerson = EnglishPerson();
    enPerson.sayHello();

    Person ruPerson = RussianPerson();
    ruPerson.sayHello();
}
Output:

Hello
Привет
  • TODO Link?

5- Các tham số tuỳ chọn

Như đã đề cập ở trên, các lớp trong DartJavascript không hỗ trợ các phương thức trùng tên, nhưng một phương thức có thể bao gồm các tham số tuỳ chọn.
Cú pháp:

// Non-static method with optional arguments:
return_type method_name(arguments, [optional_arguments])    {  
     // statement(s)  
}

// Static method with optional arguments:
static return_type method_name(arguments, [optional_arguments])    {  
     // statement(s)  
}

// Abstract method with optional arguments:
return_type method_name(arguments, [optional_arguments]);
Ví dụ:
method_optional_args_ex1.dart

class MyUtility {
  static String concat(String s1, String s2, [String? s3]) {
    if (s3 != null) {
      return s1 + s2 + s3;
    }
    return s1 + s2;
  }

  static double sum(double v1, double v2, [double? v3, double? v4]) {
    return v1 + v2 + (v3 ?? 0) + (v4 ?? 0);
  }
}

void main() {
  String result1 = MyUtility.concat('One', 'Two');
  print('result1: $result1');

  String result2 = MyUtility.concat('One', 'Two', 'Three');
  print('result2: $result2');

  double value1 = MyUtility.sum(1, 2, 3, 4);
  print('value1: $value1');

  double value2 = MyUtility.sum(1, 2, 3);
  print('value2: $value2');

  double value3 = MyUtility.sum(1, 2);
  print('value3: $value3');
}
Output:

result1: OneTwo
result2: OneTwoThree
value1: 10.0
value2: 6.0
value3: 3.0
Ví dụ:
method_optional_args_ex2.dart

class Team {
   List<String> members = [];

   void addMembers(String member1, [String? member2, String? member3]) {
      members.add(member1);
      if(member2!= null) {
         members.add(member2);
      }
      if(member3!= null) {
         members.add(member3);
      }
   }
   void printAllMembers()  {
      print(' --- All members: --- ');
      for(var member in members) {
          print(member);
      }
   }
}  

void main() {
  var team = Team(); // Create Team object:

  team.addMembers('Tom', 'Jerry');
  team.printAllMembers();
}
Output:

 --- All members: ---
Tom
Jerry
  • List

6- Ghi đè một phương thức

Lớp con có thể ghi đè (override) một phương thức cùng tên nào đó của lớp cha với điều kiện:
  • Hai phương thức phải cùng tên và có các tham số giống nhau.
  • Kiểu trả về của 2 phương thức phải giống nhau hoặc kiểu trả về của phương thức tại lớp con phải là kiểu con của kiểu trả về của phương thức tại lớp cha.
Ví dụ:
  • Lớp Cat ghi đè (override) phương thức sayAnything() của lớp Animal.
  • @override là một chú thích (annotation), nó là một tuỳ chọn được đặt phía trước của phương thức ghi đè (tại lớp con). Nếu bạn vô tình đổi tên phương thức ở lớp cha, trình biên dịch Dart sẽ thông báo điều đó cho bạn.
method_override_ex1.dart

class Animal {
  void sayAnything() {
    print('<Nothing>');
  }
}
class Cat extends Animal {
  @override
  void sayAnything() { // Override method from parent class.
    print('Meow');
  }
}

void main() {
  Animal animal = Cat();
  animal.sayAnything();
}
Output:

Meow
Ví dụ: Bạn cũng có thể sử dụng từ khoá super để gọi tới phương thức của lớp cha.
method_override_ex2.dart

class BoldFormatter {
  String formatText(String text) {
    return '<b>' + text + '</b>';
  }
}
class BoldItalicFormatter extends BoldFormatter {
  @override
  String formatText(String text) { // Override method from parent class.
    var boldText = super.formatText(text); // Call super method.
    return '<i>' + boldText + '</i>';
  }
}

void main() {
  var formatter = BoldItalicFormatter();

  var formattedText = formatter.formatText('Hello');
  print(formattedText);
}
Output:

<i><b>Hello</b></i>

7- Final method?

Trong ngôn ngữ Java, bạn có thể sử dụng từ khoá final cho một phương thức để đảm bảo rằng các lớp con không thể ghi đè (override) phương thức này. Vậy có gì đó tương tự trong Dart không?
package:meta cung cấp cho bạn @nonVirtual để ngăn chặn việc một lớp con ghi đè một phương thức nào đó của lớp cha. Nó giúp Analyzer (trình phân tích mã) thông báo vi phạm cho bạn, nhưng không có hành động nào khác được thực hiện.
method_final_ex1.dart

import 'package:meta/meta.dart';

class Foo {
   @nonVirtual
   void bar() {
     print("bar from Foo!");
   }
}

class SubFoo extends Foo {
  @override
   void bar()  {
      print("bar from SubFoo");
   }
}
Về cơ bản bạn sẽ nhận được một cảnh báo (warning) từ Analyzer giống như thế này:

The member 'bar' is declared non-virtual in 'Foo'
and can't be overridden in subclasses.dart(invalid_override_of_non_virtual_member)
  • TODO Link?

Xem thêm các chuyên mục:

Có thể bạn quan tâm

Đây là các khóa học trực tuyến bên ngoài website o7planning mà chúng tôi giới thiệu, nó có thể bao gồm các khóa học miễn phí hoặc giảm giá.