如何将业务逻辑与表示分离?

时间:2021-04-18 13:31:00

标签: kotlin

假设我有以下课程:

data class Email(val id:String,
    val from:String,
    val to:String,
    val cc: List<String> =listOf(),
    val bcc: List<String> = listOf(),
    val title: String?="",
    val message:String?="",
    val evaluation:Int?=0)

我有不同格式的数据,json、txt、csv 等。

我想为每种格式制作一个导入器。第一个选项是添加与数据格式一样多的伴随对象。 问题是类的 API 会被不必要的细节弄得杂乱无章,尤其是如果导入器在最终返回电子邮件对象之前会做一些预处理。

换句话说,我想将业务逻辑与表示分离。

  1. 我真的需要这样做吗?我来自其他语言,最佳实践可能会从一种语言更改为另一种语言。

  2. 如果是这样,最好的方法是什么。我想要一个指向知名库中一些实现的链接。

谢谢。

1 个答案:

答案 0 :(得分:1)

<块引用>
  1. 我真的需要这样做吗?我来自其他语言,最佳做法可能会从一种语言更改为另一种语言。

我认为这归结为偏好。 IMO 最好不要在域模型中包含序列化相关信息。原因是:

  • 它并不真正属于那里。正如您在问题中所说,添加所有这些映射逻辑会使 Email 类变得混乱。
  • 更改 CSV 或 JSON 解析器可能会迫使您同时更改 Email 类中的映射逻辑,从而使您的代码 more coupled

一个干净的方法是使用扩展函数。您可以选择在本地使用它们或将它们放在伴生对象中。后一个选项仍然会使您的数据类与映射逻辑混乱。

例如,如果您有一个 CsvEmailImporter 类,那么您可以编写一个私有函数,将 CSV 文件中的一行转换为 Email 对象:

    class CsvEmailImporter : EmailImporter {
      override fun import(source: InputStream): List<Email> {
        val emails = source.bufferedReader()
          .lineSequence()
          .drop(1) // don't include the csv header
          .map { it.toEmail() }
          .toList()
        return emails
      }

      private fun String.toEmail(): Email {
        // map a line in the CSV file to an Email object
      }
    }

注意在这个例子中我们的映射函数是如何私有的 CsvEmailImporter。这意味着我们不必修改 Email 类本身。这也意味着您无法从其他任何地方访问或查看它。

<块引用>
  1. 如果是这样,最好的方法是什么。我想要一个指向知名库中某些实现的链接。

我不知道这里是否有“最佳方法”,但我从一个流行的漫画阅读器应用程序中找到了 this example。 在这种情况下,有一个顶级函数可以将 Manga 对象转换为 MangaInfo 对象。该函数可从外部访问,类似于将其放入伴生对象中。

我建议尝试不同的方法,看看哪种方法最适合您和您的代码库。

相关问题