[Dart] Tìm hiểu Extension

[Dart] Tìm hiểu Extension

Extension trong Dart là một cơ chế mạnh mẽ cho phép bạn thêm các phương thức (methods), getters, setters, và operators mới vào một lớp đã tồn tại mà không cần phải sửa đổi mã nguồn của lớp đó. Điều này có nghĩa là bạn có thể mở rộng chức năng của các lớp mà bạn không sở hữu hoặc không muốn thay đổi trực tiếp (ví dụ: các lớp từ thư viện chuẩn của Dart hoặc các thư viện bên ngoài).

Tại sao cần Extension?

  • Thêm chức năng vào lớp bên ngoài: Khi bạn muốn thêm một phương thức tiện ích vào một lớp mà bạn không kiểm soát mã nguồn (ví dụ: String, List), extension là một cách an toàn và sạch sẽ để làm điều đó mà không cần tạo một lớp con hoặc một hàm tiện ích bên ngoài.
  • Code rõ ràng và dễ đọc hơn: Thay vì có các hàm tiện ích toàn cục hoạt động trên các đối tượng, bạn có thể nhóm chúng lại thành một extension, làm cho code liên quan đến một kiểu dữ liệu cụ thể trở nên dễ tìm và dễ hiểu hơn.
  • Tránh “utility class hell”: Thay vì có nhiều lớp tiện ích chứa các hàm rời rạc, extension cho phép bạn tổ chức các hàm này một cách logic hơn, gắn chúng trực tiếp với kiểu dữ liệu mà chúng thao tác.

Cú pháp của Extension:

extension TênExtension on TênLớpMởRộng {
  // Các thành viên mới (phương thức, getter, setter, operator)
}
Dart
  • extension TênExtension: Khai báo một extension với tên TênExtension. Tên này thường được sử dụng để tham chiếu đến extension nếu cần (ví dụ, để giải quyết xung đột tên).
  • on TênLớpMởRộng: Chỉ định lớp mà extension này đang mở rộng. Các thành viên bên trong extension sẽ trở thành một phần của interface công khai của lớp TênLớpMởRộng.
  • { … }: Chứa các định nghĩa của các thành viên mới mà bạn muốn thêm vào lớp.

Ví dụ:

Giả sử bạn muốn thêm một phương thức để đảo ngược một chuỗi:

extension StringReversal on String {
  String reverse() {
    return split('').reversed.join('');
  }
}

void main() {
  String myString = "hello";
  String reversedString = myString.reverse(); // Gọi phương thức reverse() như thể nó là một phần của String
  print(reversedString); // Output: olleh
}
Dart

Ví dụ với Getter:

extension StringCapitalize on String {
  String get capitalized => "${this[0].toUpperCase()}${substring(1)}";
}

void main() {
  String myString = "dart";
  print(myString.capitalized); // Output: Dart
}
Dart

Ví dụ với Operator:

class Point {
  final int x;
  final int y;

  Point(this.x, this.y);
}

extension PointAddition on Point {
  Point operator +(Point other) {
    return Point(x + other.x, y + other.y);
  }
}

void main() {
  Point p1 = Point(1, 2);
  Point p2 = Point(3, 4);
  Point sum = p1 + p2; // Sử dụng operator + đã được mở rộng
  print("(${sum.x}, ${sum.y})"); // Output: (4, 6)
}
Dart

Lưu ý quan trọng:

  • Extension là static: Các thành viên extension được giải quyết một cách tĩnh dựa trên kiểu tĩnh của receiver. Điều này có nghĩa là nếu bạn có một biến có kiểu tĩnh là lớp cha nhưng thực tế chứa một đối tượng của lớp con, các extension được định nghĩa trên lớp con sẽ không tự động có sẵn thông qua biến lớp cha đó.
  • Xung đột tên: Nếu một extension có cùng tên thành viên với một thành viên đã tồn tại trong lớp gốc hoặc một extension khác trên cùng lớp, bạn có thể gặp xung đột tên. Dart có quy tắc ưu tiên để giải quyết các xung đột này (thành viên của lớp gốc thường được ưu tiên hơn). Bạn có thể sử dụng tên extension (ví dụ: StringReversal.reverse(myString)) để gọi thành viên extension một cách rõ ràng trong trường hợp có xung đột.
  • Không thể truy cập thành viên private: Extension không thể truy cập trực tiếp vào các thành viên private (có dấu _ ở đầu tên) của lớp mà nó đang mở rộng.

Kết luận:

Extension là một tính năng mạnh mẽ trong Dart giúp bạn mở rộng chức năng của các lớp hiện có một cách an toàn và tổ chức. Nó giúp viết code sạch hơn, dễ đọc hơn và tránh việc tạo ra các lớp tiện ích lộn xộn. Đây là một công cụ hữu ích để làm việc hiệu quả với cả mã nguồn của bạn và các thư viện bên ngoài.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *