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的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 研发阶段性总结 基本设计模式BLoC

Flutter 研发阶段性总结 基本设计模式BLoC

Flutter 研发阶段性总结 基本需求研发总结

Flutter 研发阶段性总结 基本需求研发总结

Flutter 研发阶段性总结 Widget

Flutter 研发阶段性总结 Widget