在刚开始接触flutter中的BLoC 状态管理机制时,可能很多新人会对使用BlocProvider传参和使用构造函数参数传参两者有什么差异感到不解。以flutter_bloc 包中的代码举例,比如向PageB传入的Model实例,可以有如下两种方式:
- 使用BlocProvider:
class PageAState extends State{
Model modelX;
...
Widget build(BuildContext context) {
return BlocProvider.value(
value: modelX,
child: PageB(),
);
}
}
class PageB extends StatelessWidget {
Widget build(BuildContext context){
//获取Model 实例
var modelX = context.read<Model>();
...
}
}
- 使用构造函数参数:
class PageAState extends State{
Model modelX;
Widget build(BuildContext context) {
return PageB(model: modelX);
}
}
class PageB extends StatelessWidget {
PageB({required this.modelX});
final Model modeX;
Widget build(BuildContext context){
...
}
}
两种方式确实都能达到相同目的,但为何我们通常都使用第一种而不是第二种方式传递Model实例呢?再举一个例子来说明,假如要在另外一个UI中使用PageB, 该UI的层级结构如下:
class PageC extends StatelessWidget {
Widget build(BuildContext context){
return PageD();
}
}
class PageD extends StatelessWidget {
Widget bulid(BuildContext context){
return PageE();
}
}
class PageE extends StatelessWidget {
Widget build(BuildContext context){
return PageB();
}
}
在使用PageB 之前嵌套了多层Widget,这个时候如果使用参数递传的方式,那么PageC、PageD、PageE 都要增加Model的参数,但实际上它们根本用不到这个参数,只是为了向下传递而已,这就造成了一个很严重的问题:耦合,如果Model发生了变化,比如某一天PageB重构不需要Model了或Model 类型定义改变了,那么C、D、E也要跟着改,很容易造成代码的混乱。在软件设计六原则SOLID 中第一个原则:单一职责 中强调对象应专注提供单一的功能,引入无关的参数显然破坏了这一原则。所以,即使两种方式都能达到相同的目的,但从软件工程角度看,BlocProvider 方式明显优于参数递传的方式。
最近面试遇到很多新人对软件设计SOLID原则知之甚少,很多时候不理解一段看似简单的功能为什么要写那么多的代码,就没有看到背后所蕴含的架构思想,由此引出这一个小问题。很多人习惯了写功能性代码,反正功能实现了就行,主要可能因为很多项目生命周期比较短,没有暴露出相关问题。但是如果参与到了大型项目,项目周期5年以上的代码,就会切身体会到,在需求不断变化迭代过程中,代码的系统架构有多重要。当今时代很多时候实现一个功能没什么技术含量,而如何优雅的实现一个功能,永远追求一个最优方案,才是我们开发者应秉持专业素养,愿共勉。