Menu
CoddyTech

仓储模式

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 100 课,共 110 课。

仓储模式通过在应用程序和数据源之间创建抽象层,将数据访问逻辑与业务逻辑分离。你的类不再直接与数据库、API 或文件交互,而是通过仓储来处理所有数据操作。

该模式定义了数据操作的接口,具体实现负责处理实际的存储机制。这样,你就可以轻松切换数据源,而无需更改业务逻辑:

// 实体
class User {
  final int id;
  final String name;
  User(this.id, this.name);
}

// 仓库接口
abstract class UserRepository {
  User? getById(int id);
  List<User> getAll();
  void save(User user);
  void delete(int id);
}

// 内存中的实现
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
}

你的业务逻辑只依赖 UserRepository 接口。之后,你可以创建一个实现相同接口的 DatabaseUserRepository 或 ApiUserRepository,并替换实现,而无需修改任何使用该仓库的代码。这种模式对于易于测试和维护的应用至关重要,因为数据源可能会随时间变化。

challenge icon

挑战

简单

让我们使用仓储模式构建一个产品库存系统!你将创建一个抽象层,将产品的存储方式与使用方式分开,这样就能轻松更换存储实现,而无需更改业务逻辑。

你将把代码整理到两个文件中:

  • product_repository.dart:这个文件包含实体类和仓储类。先创建一个 Product 类,其中包含 final 字段:id(int)、name(String)和 price(double)。然后定义抽象类 ProductRepository,声明数据操作的约定:getById(int id) 返回一个可空的 Product,getAll() 返回产品列表,save(Product product) 用于存储产品,delete(int id) 用于删除产品。最后,创建一个 InMemoryProductRepository,使用 Map<int, Product> 存储数据,并实现这个接口。
  • main.dart:导入仓储文件,并演示仓储模式的实际用法。创建一个 InMemoryProductRepository,但将它存储在类型为 ProductRepository 的变量中,这样可以展示代码依赖的是接口,而不是具体实现。保存三个产品:Laptop(id:1,price:999.99)、Mouse(id:2,price:29.99)和 Keyboard(id:3,price:79.99)。然后获取 id 为 2 的产品,并按 Found: [name] - $[price] 的格式打印。删除 id 为 1 的产品。最后,按 Products in stock: [count] 的格式打印剩余产品的数量。

这种模式的优点在于,主代码只需要了解 ProductRepository 接口。之后,你可以创建 DatabaseProductRepository 或 ApiProductRepository,并在不更改任何业务逻辑的情况下替换当前实现!

预期输出:

Found: Mouse - $29.99
Products in stock: 2

亲手试试

import 'product_repository.dart';

void main() {
  // 创建仓库。注意,类型是接口,不是实现类。
  // TODO:创建一个 InMemoryProductRepository,并将它存入 ProductRepository 类型的变量中。
  
  // TODO:保存 3 个商品:
  // 笔记本电脑(id: 1,price: 999.99)
  // 鼠标(id: 2,price: 29.99)
  // 键盘(id: 3,price: 79.99)
  
  // TODO:获取 id 为 2 的商品并打印:"Found: [name] - $[price]"
  
  // TODO:删除 id 为 1 的商品。
  
  // TODO:打印剩余商品的数量:"Products in stock: [count]"
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器