Bloc的代码书写规范
Bloc的分包
我们之前有一张图片,如下所示:
image
我们可以看到:UI将事件给Bloc,Bloc将事件转为状态还给UI。这个工程以及完成了分离:业务层和UI层。但是呢还有一个问题:数据在哪里?如果按照上图的话,数据应该在Bloc这一层,那么就出现了一个问题:业务逻辑和数据糅合到了一起,我们理想状态应该是:数据和业务逻辑也尽可能分开。如下图所示:
image
在Bloc的模式下我们的应用可以被分为三个部分:数据 层、业务逻辑层、UI层。下面我们看一下 具体应该怎么写每一层。
数据层
数据层:从一个或多个数据源取和操作数据。数据源有:数据库、网络、文件等。数据层虽然是应用的最底层,但是也可以分为两部分:数据的获取和数据的包装。
数据获取
数据获取是为了渠道最为原始的数据,比如从网络get数据,数据库的增删改查,文件的读写等等。表现在代码上就是 某一个具体的方法。
class DataProvider {
Future<RawData> readData() async {
// Read from DB or make network request etc...
}
}
数据包装
数据包装是为了将一个数据或多个数据 糅合到一起,直接和Bloc进行交互,并且将原始数据进行处理后再交给 Bloc。体现在代码上:
class Repository {
final DataProviderA dataProviderA;
final DataProviderB dataProviderB;
Future<Data> getAllDataThatMeetsRequirements() async {
final RawDataA dataSetA = await dataProviderA.readData();
final RawDataB dataSetB = await dataProviderB.readData();
//通过两个数据 拿到业务层需要的数据
final Data filteredData = _filterData(dataSetA, dataSetB);
return filteredData;
}
}
Bloc---业务逻辑层
Bloc接受来自用户的 事件,根据事件去和上述的数据层交互,在根据交互的结果 生成对应的状态交给UI层。一个Bloc可能会依赖多个数据包装类。体现在代码上:
class BusinessLogicComponent extends Bloc<MyEvent, MyState> {
//数据包装
final Repository repository;
//事件转为状态
Stream mapEventToState(event) async* {
if (event is AppStarted) {
try {
//和数据层交互
final data = await repository.getAllDataThatMeetsRequirements();
yield Success(data);
} catch (error) {
yield Failure(error);
}
}
}
}
我们知道一个Bloc可能会依赖别他的Bloc,那怎么做到这一点呢?可以通过构造方法传参,也可以通过依赖注入。比如:
class MyBloc extends Bloc {
final OtherBloc otherBloc;
StreamSubscription otherBlocSubscription;
MyBloc(this.otherBloc) {
otherBlocSubscription = otherBloc.listen((state) {
});
}
@override
Future<void> close() {
otherBlocSubscription.cancel();
return super.close();
}
}
UI层--表现层
表现层其实就是渲染和用户交互,知道在什么样的状态下渲染出什么样的自己,知道将用户的交互事件传递给Bloc就可以了。比如:
class PresentationComponent {
final Bloc bloc;
PresentationComponent() {
bloc.add(AppStarted());
}
build() {
}
}
总结
以上就是Bloc应用的理想分层,这样看来Bloc是一个中转站:接受事件,分发事件,事件map状态。
Bloc命名
事件命名
事件最好命名为过去式,因为从Bloc的角度看,事件已经发生了。
比较常用的方式:Bloc对象+名次+动词(事件)
比如:
CounterStarted ------计数器开始了
CounterIncremented -------计数器增加了
CounterDecremented -------计数器减少了
状态命名
状态最好命名为名词,因为一个状态就是在某一时刻的一个应用快照。
比较常用的方式:Bloc对象+动词+状态,并且一般情况下状态为:Initial | Success | Failure | InProgress
比如:
CounterInitial -----计数器初始
CounterLoadInProgress -----计数器加载中
CounterLoadSuccess ------计数器加载成功
CounterLoadFailure ------计数器加载失败
网友评论