【问题标题】:Should MVP model contain android specific term?MVP 模型是否应该包含 android 特定术语?
【发布时间】:2019-03-13 16:48:45
【问题描述】:

我可以在 MVP 视图中做逻辑上的事情,但据我所知,根据 MVP 模式,视图应该尽可能地愚蠢。 MVP 模型可以包含 android 特定术语吗?如果没有,那我如何在 MVP 模型中使用活动上下文?

【问题讨论】:

  • 使用一个使用 Activity 上下文作为实现细节的类。
  • 创建一个类,接收 Context 作为构造函数参数,公开一个不知道 Context 的方法,然后在你的 Presenter 或任何你收到你的类而不是 Context 的地方。
  • 你能找到我想要实现的用例吗,我个人将活动相关值作为构造函数而不是上下文传递。
  • @ManojPerumarath 对于类似: MVP 模型中的 context.getSystemService() 。用于检查互联网连接。
  • 我所做的是创建用于网络检查的实用程序并在调用演示者方法之前使用它,我认为使用不会违反使用 MVP 的规则

标签: android android-context android-mvp


【解决方案1】:

假设基于 MVP 模式实现了一个登录功能,其中模型(LoginInteractor)将使用活动上下文。

因此,我们必须实现以下类:LoginActivityLoginPresenterImplLoginInteractorImpl(作为 MVP 模型)。正如 MVP 所述,我们将在 View 和 Presenter 之间定义一个契约。我们将它们命名为 LoginViewLoginPresenter。此外,我们还将为 Interactor 类定义一个接口,LoginInteractor

LoginActivity 具有对LoginPresenter 的引用,所有逻辑都将在其中处理。具体实现LoginPresenterImpl参考LoginViewLoginInteractor。交互器的具体实现,LoginInteractorImpl 将使用活动上下文来初始化 Android 特定资源,这些资源是收集登录过程所需数据所必需的。

这样,presenter 逻辑与 android 资源无关,并且可以轻松进行单元测试。

示例代码 sn-p(请注意,演示者如何只知道抽象交互器。具体交互器在视图中初始化,并提供它的活动上下文。)

首先,我们为所有类定义契约:

interface LoginView {

    fun onLoginSuccess()

    fun onLoginFailed()

    fun showErrorMessage(error: String)

    //...........
}

interface LoginPresenter {

    fun proceedLogin(username: String, password: String)

    //............
}

interface LoginInteractor {

    fun getUserByUsername(username: String) : User

    fun getUserCredentials() : Credential

    //............
}

然后,他们的具体实现:

class LoginActivity : LoginView, AppCompatActivity() {

    private lateinit var presenter: LoginPresenter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        // initialize presenter
        presenter = LoginPresenterImpl(
            view = this,
            interactor = LoginInteractorImpl(this)
        )

        // your code goes here
    }

    override fun onLoginSuccess() {
        // your code goes here
    }

    override fun onLoginFailed() {
        // your code goes here
    }

    override fun showErrorMessage(error: String) {
        // your code goes here
    }
}

class LoginPresenterImpl(
    private val view: LoginView,
    private val interactor: LoginInteractor
) : LoginPresenter {

    override fun proceedLogin(username: String, password: String) {
        // your custom login logic goes here
        // call interactor to get data
        // process data
        // give feedback to view
    }
}

class LoginInteractorImpl(context: Context) : LoginInteractor {

    override fun getUserCredentials() {
        // your code goes here
    }

    override fun getUserByUsername(username: String) {
        // use context to access local DB...
    }
}

注意:为了更好地分离关注点,使用依赖注入解决方案将消除视图正在初始化所有其他对象这一事实所引起的问题。

【讨论】:

  • 我在这里有 2 个问题 - a) LoginInteractorImpl 是 MVP 模型,而您在那里使用了 Context。我的困惑就在这里,这不意味着(上下文)在模型中使用android术语吗? b)您在 MVP 视图(活动)中创建了 LoginInteractorImpl 的引用,它不是在模型和视图之间创建链接吗?我是 MVP 新手,不了解这两点。
  • 是的,你是对的。为了更好地分离关注点,应该使用工厂方法和依赖注入工具,如 DaggerKoin。在某些情况下,使用上下文是不可避免的,尤其是当您的数据源是某些 android 特定资源时。您想要这样做的方式是将具体实现隐藏在抽象类/接口后面。
  • 您正在将 Context 传递给交互器,这还不错,因为它没有存储为属性。但仍然就单元测试而言,通过与特定案例更相关的东西可能会更好。如果您使用上下文来检索字符串 - 那么您可以定义 LocalizationProvider 或 StringProvider 并将其传递到交互器中。在测试中模拟会更容易,而且是更好的层分离。
猜你喜欢
  • 2012-04-08
  • 2018-04-05
  • 2018-09-04
  • 2023-03-12
  • 2012-12-06
  • 1970-01-01
  • 2015-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多