具有多个流的 Flutter Bloc?
Flutter Bloc with Multiple Streams?
我最近听说和阅读了很多关于 BLoC 架构的内容,它很有意义,并且与我以前使用的程序结构相似。
但是,我发现不清楚的一件事是 BLoC 应该实例化并提供的流。
让我们假设应用程序用户有两个按钮,按下时将创建两个 distinct 对象,需要由distinct BLoC 中的方法。我不确定这是否需要创建两个 StreamController
对象并公开两个接收器,或者它们是否应该共享一个公共 StreamController
并且这些操作在使用运行时类型检查时有所区别。
两种方法如下;第一种方法在 BLoC 中创建两个流控制器:
final _actionOneController = StreamController<ActionOne>();
StreamSink<ActionOne> get actionOne => _actionOneController.sink;
final _actionTwoController = StreamController<ActionTwo>();
StreamSink<ActionTwo> get actionTwo => _actionTwoController.sink;
通过将两个事件添加到不同的接收器来创建两个事件:
Button(child: Text("Action One"), onPressed: () => bloc.actionOne.add(ActionOne(data, data1, data3)),
Button(child: Text("Action Two"), onPressed: () => bloc.actionTwo.add(ActionTwo(someOtherData)),
并通过分别监听两个流来处理它们。
第二种方法公开了一个 StreamSink
:
final _actionController = StreamController<Action>();
StreamSink<Action> get action => _actionController.sink;
通过将这两个事件添加到公共接收器来创建它们:
Button(child: Text("Action One"), onPressed: () => bloc.action.add(ActionOne(data, data1, data3)),
Button(child: Text("Action Two"), onPressed: () => bloc.action.add(ActionTwo(someOtherData)),
然后使用检查 Action
对象的运行时类型的方法区分 BLoC 中的操作:
void _actionListener(Action action){
if(action is ActionOne)
actionOneHandler(action);
if(action is ActionTwo)
actionTwoHandler(action);
}
我想强调的是,这两个操作创建了 distinct 没有公共字段的对象,即它们不共享共同继承的祖先class.
顾名思义,BLoC 背后的核心思想是分离 UI 和业务规则之间的职责,因此取决于您希望如何构建和组织该逻辑。也许如果你为一个简单的屏幕实现一个 bloc,你会很好地使用一个流,但是随着你的应用程序变得复杂,你可能需要用与单个对象相关的逻辑将这些 bloc 分成小块,然后组合它适用于每个屏幕。
要回答这个问题,真实情况视情况而定,但正如您强调这两个操作处理不同的对象一样,建议您在不同的流中处理它以实现良好的职责分离。以后如果你需要重构和维护代码会更容易,因为你已经把所有的逻辑完全分离了。
这样做的另一个重要优势是,您可以拥有具有所有好处的强类型流,在第二种情况下,操作必须位于同一层次结构中才能添加到同一接收器。
希望对您有所帮助!
我最近听说和阅读了很多关于 BLoC 架构的内容,它很有意义,并且与我以前使用的程序结构相似。
但是,我发现不清楚的一件事是 BLoC 应该实例化并提供的流。
让我们假设应用程序用户有两个按钮,按下时将创建两个 distinct 对象,需要由distinct BLoC 中的方法。我不确定这是否需要创建两个 StreamController
对象并公开两个接收器,或者它们是否应该共享一个公共 StreamController
并且这些操作在使用运行时类型检查时有所区别。
两种方法如下;第一种方法在 BLoC 中创建两个流控制器:
final _actionOneController = StreamController<ActionOne>();
StreamSink<ActionOne> get actionOne => _actionOneController.sink;
final _actionTwoController = StreamController<ActionTwo>();
StreamSink<ActionTwo> get actionTwo => _actionTwoController.sink;
通过将两个事件添加到不同的接收器来创建两个事件:
Button(child: Text("Action One"), onPressed: () => bloc.actionOne.add(ActionOne(data, data1, data3)),
Button(child: Text("Action Two"), onPressed: () => bloc.actionTwo.add(ActionTwo(someOtherData)),
并通过分别监听两个流来处理它们。
第二种方法公开了一个 StreamSink
:
final _actionController = StreamController<Action>();
StreamSink<Action> get action => _actionController.sink;
通过将这两个事件添加到公共接收器来创建它们:
Button(child: Text("Action One"), onPressed: () => bloc.action.add(ActionOne(data, data1, data3)),
Button(child: Text("Action Two"), onPressed: () => bloc.action.add(ActionTwo(someOtherData)),
然后使用检查 Action
对象的运行时类型的方法区分 BLoC 中的操作:
void _actionListener(Action action){
if(action is ActionOne)
actionOneHandler(action);
if(action is ActionTwo)
actionTwoHandler(action);
}
我想强调的是,这两个操作创建了 distinct 没有公共字段的对象,即它们不共享共同继承的祖先class.
顾名思义,BLoC 背后的核心思想是分离 UI 和业务规则之间的职责,因此取决于您希望如何构建和组织该逻辑。也许如果你为一个简单的屏幕实现一个 bloc,你会很好地使用一个流,但是随着你的应用程序变得复杂,你可能需要用与单个对象相关的逻辑将这些 bloc 分成小块,然后组合它适用于每个屏幕。
要回答这个问题,真实情况视情况而定,但正如您强调这两个操作处理不同的对象一样,建议您在不同的流中处理它以实现良好的职责分离。以后如果你需要重构和维护代码会更容易,因为你已经把所有的逻辑完全分离了。
这样做的另一个重要优势是,您可以拥有具有所有好处的强类型流,在第二种情况下,操作必须位于同一层次结构中才能添加到同一接收器。
希望对您有所帮助!