Flutter 研发阶段性总结 基本设计模式MVP
Posted 嗡汤圆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 研发阶段性总结 基本设计模式MVP相关的知识,希望对你有一定的参考价值。
在上篇内容的基础上,我们已经可以写一些简单的应用了,但是可以预见到的是,随着页面功能的增多,函数个数、数据与页面的交互也会随之增对,随之而来的就是散落在各处的函数和setState,代码就越来越难维护了。因此需要适当的引入一些设计模式,将界面、数据与逻辑解耦。这里首先提一下MVP。
什么是MVP?
网络上文章很多。。。。。就不重复了。
Flutter上的MVP实践
这里直接拿代码说话,先说说MVP的具体实践,然后举个例子:同一个功能页面切换不同的数据源。
1. 基础MVP结构声明
Dart语言貌似是没有interface的,这里用的是abstract class。
abstract class IView<T>
setPresenter(T presenter);
abstract class IPresenter
init();
2. 声明具体页面的Presenter和View接口
假设我们有一个页面在加载的时候会从web接口获取数据并显示,同时页面可以响应用户的输入,比如上拉加载更多。则从页面行为层面我们可以抽象如下接口:
abstract class DemoPagePresenter implements IPresenter
// 初始化时候加载第一批数据
void loadData();
// 用户操作加载更多
void loadMore();
abstract class DemoPageView implements IView<DemoPagePresenter>
// 第一批数据加载成功
void onLoadSuccess(data);
// 第一批数据加载失败
void onLoadError();
// 更多数据加载成功
void onLoadMoreSuccess(data);
// 更多数据加载失败
void onLoadMoreError();
从这里可以看出, Presenter 主要负责事件驱动或者用户触发后的业务行为,在这里包括了页面初始化时候的加载数据loadData
和用户上拉列表时候的 loadMore
。
而View主要负责页面逻辑处理后的结果展现,比如加载成功、失败分别显示什么。
3. 接口的具体实现
在Presenter和View都声明完毕后,即可以开始落地具体的实现代码了。这里我们用假代码描述。
1)Presenter的具体实现
Presenter 仅关心事件驱动和用户触发后的逻辑,并决定分别另View采用何种行动,本身并不关心View长什么样。此时的View对于Presenter而言,仅仅是几个抽象的接口函数。
class DemoPagePresenterImpl implementes DemoPagePresenter
// 这里Presenter需要引入View的实例,来出发View的刷新
DemoPageView _view;
// View的实例也需要引入Presenter的实例引用
DemoPagePresenterImpl(this._view)
_view.setPresenter(this);
// 这里泛指数据的查询服务,比如可以是Dio,或者Sqlite的查询封装
DataRepository _repository;
int currentPage = 0;
@override
init()
// 初始化数据查询服务
_repository = DataRepository();
// 实现具体的业务逻辑,并决定采用何种View的操作,不关心View的函数背后的具体实现
@override
loadData()
_repository.loadByPage(currentPage).then((data)
_view.onLoadSuccess(data);
).catchError((error)
_view.onLoadError();
);
// 实现具体的业务逻辑,并决定采用何种View的操作,不关心View的函数背后的具体实现
@override
loadMore()
_repository.loadByPage(++currentPage).then((data)
_view.onLoadMoreSuccess(data);
).catchError((error)
_view.onLoadMoreError();
);
2)View的具体实现
View在Flutter中一般就和Widget绑定在一起了,让Widget implements 相应的View接口即可。注意在这里需要对View和Presenter的绑定操作做一定的处理,同时完成Presenter的init初始化。
请注意: 这里的State是View, State中的Presenter变量在State构造函数中就通过setPresenter指定好了。
这样View仅关心何时出发Presenter的业务处理代码,但是具体业务代码是如何实现的View并不关心。
class DemoPage extends StatefulWidget
@override
_DemoPageState createState()
_DemoPageState view = new _DemoPageState();
// 在这里初始化Presenter,同时与View建立绑定关系
DemoPagePresenter presenter = new DemoPagePresenterImpl(view);
presenter.init();
return view;
class _DemoPageState extends State<DemoPage> implementes DemoPageView
DemoPagePresenter _presenter;
List _resultList = List();
@override
Widget build(BuildContext context)
return Column(
children: <Widget>[
RaisedButton(
onPressed: () _presenter.loadMore(); ,
child: Text('Press to load more')
),
ListView.builder(
itemCount: _resultList.length,
builder: (context, index)
return Text(_resultList[index]);
),
]
);
@overrid
setPresenter(DemoPagePresenter presenter)
_presenter = presenter;
@overrid
initState()
super.initState();
// 初始化加载第一批数据
_presenter.loadData();
@override
onLoadSuccess(data)
setState(()
_resultList = data;
);
@override
onLoadError()
print('error!');
@override
onLoadMoreSuccess(data)
setState(()
_resultList.addAll(data);
);
@override
onLoadMoreError()
print('load more error!');
进阶:切换数据源
改需求最直接的反映就是开发环境和生产环境的切换了,在上边的例子来说就是根据需求切换DataRepository的不同实现类即可。这里截取部分片段
// 这里泛指数据的查询服务,比如可以是Dio,或者Sqlite的查询封装
DataRepository _repository;
int currentPage = 0;
@override
init()
// 初始化数据查询服务
// _repository = DataRepository();
// 修改为如下:
if(appConstants.production)
_repository = DataRepositoryProductionImpl();
else
_repository = DataRepositoryDevelopmentImpl();
以上是关于Flutter 研发阶段性总结 基本设计模式MVP的主要内容,如果未能解决你的问题,请参考以下文章