仓储模式
本课属于 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,并替换实现,而无需修改任何使用该仓库的代码。这种模式对于易于测试和维护的应用至关重要,因为数据源可能会随时间变化。
挑战
简单让我们使用仓储模式构建一个产品库存系统!你将创建一个抽象层,将产品的存储方式与使用方式分开,这样就能轻松更换存储实现,而无需更改业务逻辑。
你将把代码整理到两个文件中:
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]"
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器