Menu
CoddyTech

Mẫu Repository

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 100 trên 110.

Mẫu Repository tách logic truy cập dữ liệu khỏi logic nghiệp vụ bằng cách tạo một lớp trừu tượng giữa ứng dụng và nguồn dữ liệu. Thay vì để các lớp tương tác trực tiếp với cơ sở dữ liệu, API hoặc tệp, chúng làm việc với một repository xử lý mọi thao tác dữ liệu.

Mẫu này định nghĩa một giao diện cho các thao tác dữ liệu, còn các phần triển khai cụ thể xử lý cơ chế lưu trữ thực tế. Nhờ vậy, bạn có thể dễ dàng thay đổi nguồn dữ liệu mà không cần sửa logic nghiệp vụ:

// Thực thể
class User {
  final int id;
  final String name;
  User(this.id, this.name);
}

// Giao diện repository
abstract class UserRepository {
  User? getById(int id);
  List<User> getAll();
  void save(User user);
  void delete(int id);
}

// Triển khai trong bộ nhớ
class InMemoryUserRepository implements UserRepository {
  final Map<int, User> _users = {};

  @override
  User? getById(int id) => _users[id];

  @override
  List<User> getAll() => _users.values.toList();

  @override
  void save(User user) => _users[user.id] = user;

  @override
  void delete(int id) => _users.remove(id);
}

void main() {
  UserRepository repo = InMemoryUserRepository();
  
  repo.save(User(1, 'Alice'));
  repo.save(User(2, 'Bob'));
  
  print(repo.getById(1)?.name);  // Alice
  print(repo.getAll().length);    // 2
}

Logic nghiệp vụ của bạn chỉ phụ thuộc vào giao diện UserRepository. Sau này, bạn có thể tạo DatabaseUserRepository hoặc ApiUserRepository triển khai cùng giao diện, rồi thay đổi cách triển khai mà không cần sửa bất kỳ code nào sử dụng repository. Mẫu này rất cần thiết để xây dựng ứng dụng dễ kiểm thử, dễ bảo trì, trong đó nguồn dữ liệu có thể thay đổi theo thời gian.

challenge icon

Thử thách

Dễ

Hãy xây dựng hệ thống quản lý hàng tồn kho bằng mẫu Repository nhé! Bạn sẽ tạo một lớp trừu tượng để tách biệt cách lưu trữ sản phẩm với cách sử dụng chúng, giúp bạn dễ dàng thay đổi cách triển khai lưu trữ mà không cần sửa logic nghiệp vụ.

Bạn sẽ sắp xếp code vào hai tệp:

  • product_repository.dart: Tệp này chứa lớp thực thể và các lớp repository. Bắt đầu bằng lớp Product có các trường final cho id (int), name (String) và price (double). Sau đó, định nghĩa lớp trừu tượng ProductRepository để khai báo các thao tác dữ liệu: getById(int id) trả về một Product có thể có giá trị null, getAll() trả về một danh sách sản phẩm, save(Product product) để lưu sản phẩm và delete(int id) để xóa một sản phẩm. Cuối cùng, tạo InMemoryProductRepository triển khai giao diện này bằng Map<int, Product> để lưu trữ.
  • main.dart: Nhập tệp repository và minh họa cách mẫu Repository hoạt động. Tạo một InMemoryProductRepository nhưng lưu nó trong một biến có kiểu ProductRepository. Điều này cho thấy code của bạn phụ thuộc vào giao diện, không phải cách triển khai. Lưu ba sản phẩm: Laptop (id: 1, price: 999.99), Mouse (id: 2, price: 29.99) và Keyboard (id: 3, price: 79.99). Sau đó, truy xuất và in ra sản phẩm có id 2 theo định dạng Found: [name] - $[price]. Xóa sản phẩm có id 1. Cuối cùng, in ra số lượng sản phẩm còn lại theo định dạng Products in stock: [count].

Điểm mạnh của mẫu này là code chính chỉ cần biết về giao diện ProductRepository. Sau này, bạn có thể tạo DatabaseProductRepository hoặc ApiProductRepository rồi thay thế mà không cần sửa logic nghiệp vụ!

Kết quả dự kiến:

Found: Mouse - $29.99
Products in stock: 2

Tự làm thử

import 'product_repository.dart';

void main() {
  // Tạo repository. Lưu ý kiểu dữ liệu là interface, không phải phần triển khai.
  // TODO: Tạo một InMemoryProductRepository và lưu vào biến ProductRepository.
  
  // TODO: Lưu ba sản phẩm:
  // - Laptop (id: 1, price: 999.99)
  // - Mouse (id: 2, price: 29.99)
  // - Keyboard (id: 3, price: 79.99)
  
  // TODO: Lấy sản phẩm có id 2 và in ra: "Found: [name] - $[price]"
  
  // TODO: Xóa sản phẩm có id 1.
  
  // TODO: In ra số sản phẩm còn lại: "Products in stock: [count]"
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online