You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bloc事件与Clean Architecture用例是否等同?合并方案及合理性探讨

Bloc事件与Clean Architecture用例的合并疑问

代码示例

Clean Architecture用例代码

final class AuthUseCases {
  final DataProxy dataProxy;

  const AuthUseCases(this.dataProxy);

  Future<AuthSession> login(TCredential credential) async {
    // a lot of lines here...
  }

  AuthSession logout(AuthSession session) {
    // a few lines here...
  }
}

Freezed实现的Bloc事件代码

@freezed
sealed class TmdbEvent with _$TmdbEvent {
  const factory TmdbEvent.login(TCredential credential) = LoginEvent;
  const factory TmdbEvent.logout() = LogoutEvent;
}

class TmdbBloc extends Bloc<TmdbEvent, PageState> {
  // more lines here...
}

疑问

我认为Bloc事件与Clean Architecture用例是相同的,因此考虑将这两类合并,现提出以下问题:

  1. 该观点是否正确?
  2. 若合并,新类应如何编写?(我刚接触Freezed包)
  3. 合并为单个类还是分开维护更合适?

解答

1. 观点是否正确?

不完全正确。Bloc事件本质是UI层触发的动作指令,仅负责传递触发操作的必要数据,本身不包含业务逻辑;而Clean Architecture的用例是业务逻辑的封装载体,包含具体的业务规则、数据交互逻辑,属于领域层/业务层的核心组件。

两者只是在命名、触发动作上存在对应关系,但职责边界完全不同:Bloc事件是"告诉Bloc要做什么",用例是"具体怎么做",属于分层架构中不同层级的产物。

2. 若尝试合并,如何编写?

如果硬要合并,核心思路是让Freezed生成的事件类同时承载用例的业务逻辑,但这种写法会打破分层原则,仅做技术演示:

@freezed
sealed class AuthEvent with _$AuthEvent {
  // 注入数据代理,Freezed类通常不建议直接持有依赖,这里是为了合并的妥协
  final DataProxy dataProxy;

  const AuthEvent._(); // 必须定义私有构造函数才能添加自定义方法

  const factory AuthEvent.login(TCredential credential, DataProxy dataProxy) = LoginEvent;
  const factory AuthEvent.logout(AuthSession session, DataProxy dataProxy) = LogoutEvent;

  // 把原用例的业务逻辑放到事件的方法中
  Future<AuthSession> executeLogin() async {
    if (this is LoginEvent) {
      final event = this as LoginEvent;
      // 原login用例的业务逻辑代码
      // ...
      return AuthSession();
    }
    throw StateError("Invalid event type");
  }

  AuthSession executeLogout() {
    if (this is LogoutEvent) {
      final event = this as LogoutEvent;
      // 原logout用例的业务逻辑代码
      // ...
      return event.session;
    }
    throw StateError("Invalid event type");
  }
}

在Bloc中的使用方式:

class AuthBloc extends Bloc<AuthEvent, PageState> {
  AuthBloc() : super(InitialState()) {
    on<AuthEvent>((event, emit) async {
      if (event is LoginEvent) {
        final session = await event.executeLogin();
        emit(LoggedInState(session));
      } else if (event is LogoutEvent) {
        event.executeLogout();
        emit(LoggedOutState());
      }
    });
  }
}

⚠️ 注意:这种写法违背了Clean Architecture的分层思想,把业务逻辑耦合到了UI层的事件类中,后续维护、测试都会变得困难,不推荐在实际项目中使用。

3. 合并还是分开维护?

强烈建议分开维护,原因如下:

  • 职责单一:用例专注业务逻辑,可独立测试、复用(比如除了Bloc,其他业务场景也能调用用例);Bloc事件专注传递动作指令,保持轻量。
  • 分层清晰:符合Clean Architecture的分层原则,领域层(用例)不依赖UI层(Bloc事件),降低模块间耦合。
  • 可扩展性:后续新增业务逻辑只需修改用例,新增UI触发动作只需新增Bloc事件,互不影响。

内容的提问来源于stack exchange,提问作者Ουιλιαμ Αρκευα

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 03:28:30