Flutter 块架构设计

Posted

技术标签:

【中文标题】Flutter 块架构设计【英文标题】:Flutter bloc architecture design 【发布时间】:2021-10-22 20:26:24 【问题描述】:

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

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

DataProviders:从两种不同文件格式之一读取数据(本地) 存储库:解析数据并实例化我的模型 ProjectCubit:从 FilePicker 获取路径并从上 2 层获取项目

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 不好,为什么?

不胜感激,谢谢

【问题讨论】:

【参考方案1】:

最佳做法取决于您想要完成的任务。 如果您希望您的应用程序在未来扩展,让几个人一起工作,以促进更好的可重用性和更好的可测试性,建议尽可能将业务逻辑和 UI 分开。因此,直接在表示层中有逻辑是没有意义的。当您使用 cubit 时,您会希望在您的程序中保持一致并尽可能地让 UI 和逻辑解耦。

这当然是有代价的。您需要投入更多时间并使您的代码比以前更复杂。

至于您的答案,我建议使用ProjectCubit 并根据您的要求实施几个事件,例如CustomerChangeEvent 用于更改客户。

如果您有任何特殊要求需要在两个页面中以不同方式实现,那么我建议从基类继承或仅使用 mixin 并将该类扩展为不同的 cubits。

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) 
    ...
  

【讨论】:

非常感谢,但是,如果我使用 mixin 或 Baseclass 子类模型,我将如何让它们共享同一个 Project 实例?现在我基本上调用 openProject() 一次,并且需要为其他肘的所有操作创建的实例。 我刚刚创建了一个 ProjectSettingsCubit,它似乎可以工作。谢谢! 我明白了。如果要共享项目实例,可以将项目用作基类中的静态字段。或者正如您自己所说,分享projectCubit 本身。 我真的很困惑,因为我认为它会按值传递,而不是按引用传递,并且在使用 Project 而不是 ProjectCubit 时我只会编辑一个副本,但它似乎工作,得看看Dart 如何再次传递变量

以上是关于Flutter 块架构设计的主要内容,如果未能解决你的问题,请参考以下文章

Flutter架构设计

Flutter架构设计

Flutter架构设计

浅析Flutter的架构设计

Flutter IM跨端架构设计和实现

软件架构和设计模式