Android开发中的MVP架构

Android开发中的MVP架构

这篇文章背后的故事

原文链接 MVP Architecture in Android Development

最近,越来越多的Android开发人员似乎在讨论架构。我周围的同事和工程师也是如此。虽然我对MVP和DDD不太了解,但我们的新项目决定以MVP架构为基础。

这个帖子是我从各种职位和讨论中研究和学习的,其中包括:

  • 为什么越来越多的人在谈论这个架构?

  • 什么是MVP,首先是什么?

  • MVC,MVVM或MVP?哪一个是最好的?

  • MVP的利与弊

  • 上代码!

还有,这是这篇文章不包括的内容

  • 详细的可运行的样例代码
  • 如何编写测试代码

文章的最后,我会告诉你进一步阅读这些主题

顺便说一下,我上周在一个关于MVP架构的地方研讨会上发表了讲话。这个帖子也是为了与演讲对应。

介绍〜Activity是上帝〜

首先,让我们来谈谈Android开发提出简洁架构的必要性的根本原因。

以下是“Code Complete 2nd Edition”的摘录:

Avoid creating god classes Avoid creating omniscient classes that are all-knowing and all-powerful. If a class spends its time retrieving data from other classes using Get() and Set() routines ( that is, digging into their business and telling them what to do ), ask whether that functionality might better be organized into those other classes rather than into the god class ( Riel 1996 ).

God Class很难维护,了解发生了什么,执行单元测试,扩展阶段等等。这是避免创造god classes的黄金规则。

然而,在Android开发中,如果您不太在意架构,那么Activity类往往会越来越大.这是因为在Android中,View和其他线程可以在Activity类中共存。最大的问题?业务逻辑和UI逻辑在Activity类中共存。 这导致了单元测试或维护性的困难。

Activity is god

这是需要简洁架构的原因之一。不仅活动类的扩展,还有其他问题,如Activity和Fragment类中的复杂生命周期,数据绑定等。

什么是MVP?

MVP代表Model, View, and Presenter.

  • View 是一个处理所有用户操作并显示每个视图部分的图层。在Android上,这可以是Activity和Fragment类。

  • Model是负责数据访问的层。数据是从哪里来的。例如远程服务器API,本地数据库,如SQL,SharedPreferences等。

  • Presenter是在View和Model模式之间桥接(或适配器)数据的层。

The Dependency Injection

关键是,较高的接口不了解较低的接口,或者更准确地说,较高的接口不能,不应该也不能知道较低的接口的细节。是的,信息隐藏。

The higher interfaces do not know about the details of the lower ones

依赖规则?

Uncle Bob的 “The Clean Architecture” 对于依赖规则是非常有用的。

The concentric circles represent different areas of software. In general, the further in you go, the higher level the software becomes. The outer circles are mechanisms. The inner circles are policies.

以下是上述帖子的摘录:

Entities

  • 可以是一个带有方法的对象
  • 可以是一组数据结构和功能
  • 只要这些实体可以被企业中的许多不同的应用程序使用就是没问题的。

Use Cases 用例

  • 包含应用程序的业务规则
  • 协调数据流往实体的流程
  • 指导这些实体使用企业范围的业务规则来实现用例的目标

Presenters, Controllers

  • 从用例和实体最方便的格式转换数据,
  • 转换到一些外部代理(如DB或Web)最方便的格式
  • 完全包含一个GUI的MVC架构

外部接口,UI,DB

  • 所有的细节都在哪里
  • 如DB,Web框架等。

MVC,MVP还是MVVM?

那么哪一个是最好的?哪一个优于其他人?我应该选择其他中的唯一一个的吗?

答案是 不。

这些模式的动机是一样的。如何避免复杂的结构混乱的代码,让您轻松执行单元测试,并创建更高品质的应用程序。而已。

当然,除了三种以外,还会有更多的模式。他们中的每一个都不是杀手锏,也不是唯一的答案。它们是方法论之一。解决问题的一个方法。不要把手段变成目的。

利弊

好的,让我们回到MVP架构。刚才,我们已经看到了MVP是什么,现在我们趁热打铁来讨论MVP或其他体系结构,以及MVC,MVP和MVVM之间的区别。

优点

  • 可测试(导致TDD)
  • 可维护(代码重用)
  • 容易得到审查
  • 信息隐藏

缺点

  • 冗长,特别是当应用程序大小小的时候
  • 额外的学习曲线(也许)
  • 在开始编码之前需要时间(但我敢打赌,架构是所有开发必须的步骤)

口说无凭,代码为证

这里只显示MVP模式的最小结构。如果您想看到更多的例子或活泼的例子,请参考最后的“链接和资源”一章。这里只显示MVP模式的最小结构。如果您想看到更多的例子或活泼的例子,请参考最后的“链接和资源”一章。有更多丰富和精心设计的示例,基本上托管在Github中,以便您可以克隆并查看其在设备上的工作原理。

首先,我们定义每个视图的接口。

/**
 * Interface classes for the Top view
 */
public interface TopView {

    /**
     * Initialize the view.
     * 
     * e.g. the facade-pattern method for handling all Actionbar settings
     */
    void initViews();

    /**
     * Open {@link DatePickerDialog}
     */
    void openDatePickerDialog();

    /**
     * Start ListActivity
     */
    void startListActivity();
}

让我们覆盖TopView类。这里的关键是:

  • TopActivity仅处理事件侦听器或显示每个视图部分
  • 必须将所有业务逻辑委派给Presenter类
  • 在MVP中,View和Presenter类被声明为1对1(在MVVM中,在某些方面为1)

public class TopActivity extends Activity implements TopView {

    // here we use ButterKnife to inject views
    /**
     * Calendar Title
     */
    @Bind(R.id.calendar_title)
    TextView mCalendarTitle;
    
    private TopPresenter mTopPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_top);
        ButterKnife.bind(this);
        
        // Save TopPresenter instance in a meber variable field
        mTopPresenter = new TopPresenter();
        mTopPresenter.onCreate(this);
    }

    /*
     * Overrides method from the {@link TopView} interfaces
     */

    @Override
    public void initViews() {
        // Actionbar settins
        
        // set event listeners
    }

    @Override
    public void openDatePickerDialog() {
        DatePickerFragment.newInstance().show(getSupportFragmentManager(),
                DatePickerFragment.TAG);
                
        // do not write logic here... all logic must be passed to the Presenter
        mTopPresenter.updateCalendarDate();
    }

    @Override
    public void startListActivity() {
        startActivity(new Intent(this, ListActivity.class));
    }
}

这是Presenter类。最重要的是,presenter 只能在模型和视图之间使用适配器。例如,TopPresenter隐藏了“TopUseCase#saveCalendarDate()”,TopView也是如此。您不必关心数据结构是什么,以及业务逻辑如何工作。因此,您可以执行TopUseCase的单元测试,因为业务逻辑与View层分离。

public class TopPresenter {

    @Nullable
    private TopView mView;
    
    private TopUseCase mUseCase;
    
    public TopPresenter() {
      mUseCase = new TopUseCase();
    }
    
    public void onCreate(@NonNull TopView topView) {
        mView = topView;
        
        // here you call View's implemented methods
        mView.initViews();
    }

    public void updateCalendarDate() {
        // do not forget to return if view instances is null
        if (mView == null) {
            return;
        }

        // here logic comes
        String dateToDisplay = mUseCase.getDateToDisplay(mContext.getResources());
        mView.updateCalendarDate(dateToDisplay);
        
        // here you save date, and this logic is hidden in UseCase class
        mUseCase.saveCalendarDate();
    }

}

是的,您当然可以执行单元测试,即使业务逻辑在Activity类中实现,但这需要更多的时间和复杂性。运行应用程序可能需要更多时间。相反,您应该充分利用单元测试库的力量,如Robolectric

结论

没有杀手锏,而MVP本身就是其中之一。它可以与其他方法混合使用,同时也可以选择性地用于每个项目。

链接和资源

Uncle Bob 的 The Clean Architecture

这是 Uncle Bob的帖子,描述依赖规则是什么,以及每个组件之间的工作原理。我开始说的图形是受他的帖子的启发。虽然这并不是一直以Android开发为重点,但他的话语意味深长并且组织的也不错。必须读一个。

Fernando Cejas 的Architecting Android…The clean way?

我认为这是最着名和最受欢迎的博客文章,解释如何将MVP架构纳入Android开发。我也从他易于阅读和写得很好的博客文章中看到了“MVP”这个词。每个想要了解MVP架构如何在真实应用程序中工作的Android开发人员,他的Github示例代码应该被克隆。

Thanos Karpouzis 的 Android Architecture

MVC,MVP和MVVM在Android项目上的简单指南。我从他平凡但广泛覆盖的帖子中学到了很多,特别是MVC,MVP和MVVM之间的差异。

Software Design patterns on Android English

这是Karumi的高级Android开发人员的一个演讲,它从一些设计模式(例如Renderer Pattern,Repository Pattern and Command Pattern)解释MVP架构。如果你想扩大你对MVC或MVP的研究,这是你正在寻找的。

Artem Zinnatullin 的M — Model in MVC, MVP, MVVC in Android

如果您还对模型图层中的JSON或SQL有一些误解,或者没有获取关于模型图层的精确认识,这篇文章引导您进一步了解模型层与其他层之间的区别。他的“模型层是解决方案”部分特别适合展示如何将代码从接口实现到测试的实例。

--

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容