Flutter bloc架构设计
Flutter bloc architecture design
这不是关于具体实施,而是关于良好实践。
我在一个flutter桌面项目中有如下结构:
- DataProviders:从两种不同文件格式之一读取数据(本地)
- 存储库:解析数据并实例化我的模型
- ProjectCubit:从FilePicker中获取路径,从上2层获取Project
ProjectCubit.dart:
class ProjectCubit extends Cubit<ProjectState> {
ProjectCubit() : super(ProjectState.Closed);
Project? loadedProject;
Project? getProject() {
// return loaded instance of Project if loaded
if(loadedProject != null)
return loadedProject;
}
// creates Project instance from csv file
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
// open json-Project file
void openProject(String filePath) async {
emit(ProjectState.Opening);
try {
loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.OPEN_PROJECT_FILE, filePath: filePath);
} catch (e) {
emit(ProjectState.Closed);
Log().l.e("Opening file failed with ${e.toString()}");
}
emit(ProjectState.Open);
}
}
其中的州是:
enum ProjectState {
Closed,
Importing,
Opening,
Open
}
ProjectCubit 中的项目实例需要在多个设置(数据表、简单输入等)中从多个屏幕进行访问和更改。例如,Project 有一个 Customer,它有一个 customerName、customerId 等,必须从 Customer-Settings 屏幕进行更改。
我想到了两个办法:
- 创建一个 ProjectSettingsCubit、CustomerDataCubit、ProjectDataCubit 等,将 ProjectCubit 作为参数并从那里修改项目
- 一直使用 ProjectCubit 并从表示层进行更改
完成此任务的最佳方法是什么?如果整个结构或 Cubit 不好,为什么?
非常感谢任何帮助,谢谢
最佳做法取决于您要实现的目标。
如果你希望你的应用程序在未来扩展,有几个人在上面工作,促进更好的可重用性和更好的可测试性,建议尽可能分离业务逻辑 & UI。因此,直接在表示层中包含逻辑是没有意义的。当您使用 cubit 时,您会希望在您的程序中保持一致并尝试让 UI 和逻辑尽可能地解耦。
这当然是有代价的。您需要投入更多时间并使您的代码比以前更复杂。
至于你的回答,我建议使用 ProjectCubit
并根据你的要求实施几个事件,例如 CustomerChangeEvent
用于更改客户。
如果您有任何需要在两个页面中以不同方式实现的特殊要求,那么我建议从基础 class 继承,或者只使用 mixin 并在不同的 cubits 中扩展 class。
class BaseProjectCubit extends Cubit<ProjectState> {
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType:
ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
...
}
class ProjectCubitA extends BaseProjectCubit {
@override
void importProject(String filePath) async {
...
}
}
class ProjectCubitB extends BaseProjectCubit {
importProject(String filePath) async {
...
}
}
或者对于使用 mixins,它会是这样的:
mixin ProjectModifier {
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType:
ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
...
}
class CustomerTypeOneProjectCubit extends Cubit<ProjectState> with ProjectModifier {
changeName(String newName) {
...
}
}
class CustomerTypeTwoProjectCubit extends Cubit<ProjectState> with ProjectModifier {
changeName(String newName) {
...
}
}
这不是关于具体实施,而是关于良好实践。
我在一个flutter桌面项目中有如下结构:
- DataProviders:从两种不同文件格式之一读取数据(本地)
- 存储库:解析数据并实例化我的模型
- ProjectCubit:从FilePicker中获取路径,从上2层获取Project
ProjectCubit.dart:
class ProjectCubit extends Cubit<ProjectState> {
ProjectCubit() : super(ProjectState.Closed);
Project? loadedProject;
Project? getProject() {
// return loaded instance of Project if loaded
if(loadedProject != null)
return loadedProject;
}
// creates Project instance from csv file
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
// open json-Project file
void openProject(String filePath) async {
emit(ProjectState.Opening);
try {
loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.OPEN_PROJECT_FILE, filePath: filePath);
} catch (e) {
emit(ProjectState.Closed);
Log().l.e("Opening file failed with ${e.toString()}");
}
emit(ProjectState.Open);
}
}
其中的州是:
enum ProjectState {
Closed,
Importing,
Opening,
Open
}
ProjectCubit 中的项目实例需要在多个设置(数据表、简单输入等)中从多个屏幕进行访问和更改。例如,Project 有一个 Customer,它有一个 customerName、customerId 等,必须从 Customer-Settings 屏幕进行更改。
我想到了两个办法:
- 创建一个 ProjectSettingsCubit、CustomerDataCubit、ProjectDataCubit 等,将 ProjectCubit 作为参数并从那里修改项目
- 一直使用 ProjectCubit 并从表示层进行更改
完成此任务的最佳方法是什么?如果整个结构或 Cubit 不好,为什么?
非常感谢任何帮助,谢谢
最佳做法取决于您要实现的目标。 如果你希望你的应用程序在未来扩展,有几个人在上面工作,促进更好的可重用性和更好的可测试性,建议尽可能分离业务逻辑 & UI。因此,直接在表示层中包含逻辑是没有意义的。当您使用 cubit 时,您会希望在您的程序中保持一致并尝试让 UI 和逻辑尽可能地解耦。
这当然是有代价的。您需要投入更多时间并使您的代码比以前更复杂。
至于你的回答,我建议使用 ProjectCubit
并根据你的要求实施几个事件,例如 CustomerChangeEvent
用于更改客户。
如果您有任何需要在两个页面中以不同方式实现的特殊要求,那么我建议从基础 class 继承,或者只使用 mixin 并在不同的 cubits 中扩展 class。
class BaseProjectCubit extends Cubit<ProjectState> {
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType:
ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
...
}
class ProjectCubitA extends BaseProjectCubit {
@override
void importProject(String filePath) async {
...
}
}
class ProjectCubitB extends BaseProjectCubit {
importProject(String filePath) async {
...
}
}
或者对于使用 mixins,它会是这样的:
mixin ProjectModifier {
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType:
ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
...
}
class CustomerTypeOneProjectCubit extends Cubit<ProjectState> with ProjectModifier {
changeName(String newName) {
...
}
}
class CustomerTypeTwoProjectCubit extends Cubit<ProjectState> with ProjectModifier {
changeName(String newName) {
...
}
}