Flutter bloc架构设计

Flutter bloc architecture design

这不是关于具体实施,而是关于良好实践。

我在一个flutter桌面项目中有如下结构:

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 屏幕进行更改。

我想到了两个办法:

完成此任务的最佳方法是什么?如果整个结构或 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) {
    ...
  }
}