Scala设计模式UML图例和代码实现实战 行为模式--模板方法设计模式

 

 

模板方法设计模式  示例类图

模板方法设计模式适用于实现框架。这里典型的是算法通常执行相同的步骤集,然后这些步骤由不同的客户端以不同的方式实现。您可以提出各种可能的用例。
对于我们的示例,让我们假设我们要编写一个应用程序,它将从数据源中读取一些数据,解析它,并查找是否存在满足某些条件的对象并将其返回。如果我们考虑它,我们有以下主要操作:读取数据解析数据搜索满足条件的项目如果需要,清理所有资源下图显示了我们代码的类图:我们使用了一个示例,我们'已经显示了从文件中读取有关人​​员的数据。然而,在这里,我们使用它来查找满足过滤功能的人的数据。使用模板方法设计模式,我们可以从服务器,数据库或任何想到的东西中读取具有不同格式的文件的人员列表。使用多态,我们的应用程序确保调用正确的方法,一切正常。代码示例让我们通过代表上图的代码,看看它的作用。

case class Person(name: String, age: Int, address: String)
import java.io.{InputStreamReader, ByteArrayInputStream}

import com.github.tototoshi.csv.CSVReader
import com.ivan.nikolov.behavioral.template.model.Person
import org.json4s.{StringInput, DefaultFormats}
import org.json4s.jackson.JsonMethods

abstract class DataFinder[T, Y] {

  def find(f: T => Option[Y]): Option[Y] =
    try {
      val data = readData()
      val parsed = parse(data)
      f(parsed)
    } finally {
      cleanup()
    }

  def readData(): Array[Byte]

  def parse(data: Array[Byte]): T

  def cleanup()
}

class JsonDataFinder extends DataFinder[List[Person], Person] {
  implicit val formats = DefaultFormats

  override def readData(): Array[Byte] = {
    val stream = this.getClass.getResourceAsStream("people.json")
    Stream.continually(stream.read).takeWhile(_ != -1).map(_.toByte).toArray
  }

  override def cleanup(): Unit = {
    System.out.println("Reading json: nothing to do.")
  }

  override def parse(data: Array[Byte]): List[Person] =
    JsonMethods.parse(StringInput(new String(data, "UTF-8"))).extract[List[Person]]
}

class CSVDataFinder extends DataFinder[List[Person], Person] {
  override def readData(): Array[Byte] = {
    val stream = this.getClass.getResourceAsStream("people.csv")
    Stream.continually(stream.read).takeWhile(_ != -1).map(_.toByte).toArray
  }

  override def cleanup(): Unit = {
    System.out.println("Reading csv: nothing to do.")
  }

  override def parse(data: Array[Byte]): List[Person] =
    CSVReader.open(new InputStreamReader(new ByteArrayInputStream(data))).all().map {
      case List(name, age, address) =>
        Person(name, age.toInt, address)
    }
}


object DataFinderExample {
  def main(args: Array[String]): Unit = {
    val jsonDataFinder: DataFinder[List[Person], Person] = new JsonDataFinder
    val csvDataFinder: DataFinder[List[Person], Person] = new CSVDataFinder

    System.out.println(s"Find a person with name Ivan in the json: ${jsonDataFinder.find(_.find(_.name == "Ivan"))}")
    System.out.println(s"Find a person with name James in the json: ${jsonDataFinder.find(_.find(_.name == "James"))}")

    System.out.println(s"Find a person with name Maria in the csv: ${csvDataFinder.find(_.find(_.name == "Maria"))}")
    System.out.println(s"Find a person with name Alice in the csv: ${csvDataFinder.find(_.find(_.name == "Alice"))}")
  }
}

运行结果如下:

首先,我们的模型Person类:case类Person(name:String,age:Int,address:String)没有什么特别之处。现在,让我们转到有趣的部分 - DataFinder类:我们使用泛型来使这个类可用于各种类型。正如您在前面的代码中看到的那样,DataFinder类的三个方法没有实现,但它们仍然在find方法中引用。后者是实际的模板方法,抽象方法将在扩展DataFinder的不同类中实现。
对于我们的示例,我们提供了两种不同的实现,一种用于JSON,另一种用于CSV文件。 JSON查找器看起来如下:每当我们使用它时,根据我们具有的具体实例,find方法将通过多态调用正确的实现。可以通过扩展DataFinder类来添加新格式和数据源。
使用我们的数据查找器现在很简单:我们示例中的代码使用抽象类。这使得它在某种意义上略有限制,即我们只能扩展一个类。
但是,将抽象类更改为特征然后将其混合到类中会很简单。
它有什么好处正如您所看到的,每当我们有一个算法结构相同且我们提供不同实现的用例时,我们就可以使用模板方法设计模式。这非常适合创建框架。
它不是那么好用每当我们使用模板方法设计模式实现的框架变大时,简单地扩展一个庞大的类并实现它的一些方法就更难了。在这些情况下,将接口传递给构造函数并在框架中使用它可能是一个更好的想法(策略设计模式)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开心自由天使

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值