实现策略模式的功能方式 [英] Functional way to implement strategy pattern

查看:83
本文介绍了实现策略模式的功能方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解决从一个温度单位到另一个温度单位(摄氏温度,开尔文温度,华氏温度)的转换问题。

I am trying to solve a problem that handles conversion from one Temperature Unit to the other(Celsius, Kelvin, Fahrenheit).

在Java中,我需要创建一个接口,并提供封装输入类型并以输出类型为单位返回结果的多个实现。例如,将Kelvin转换为Celsius,或将celsius转换为华氏温度等。保持代码正常运行并遵循开放式封闭原则
请忽略转换逻辑

In Java I need to create an interface and provide multiple implementations that encapsulate the Input Type and return the result as a unit of the output type. e.g Kelvin to Celsius or celsius to fahrenheit etc. I have refactored my code in scala to following but still I feel it breaks the Open closed principle, since in case I need to add another type I need to change the existing code.Any suggestions to keep the code functional as well as adherent to the Open closed principle Please ignore the logic for conversion

    object TempConverter extends App {

  object UnitType extends Enumeration {
    type EnumType = Value
    val cel, fah, kel = Value
  }

  def convert(x: Double, i:UnitType.Value,o:UnitType.Value) = {
    strategy(i,o)(x)
  }

  def strategy(inputType: UnitType.Value, outputType: UnitType.Value) = {
    inputType match {
      case UnitType.cel => celsius(outputType)
      case UnitType.kel => kelvin(outputType)
      case UnitType.fah => fahrenheit(outputType)
    }
  }


  def celsius(outputType: UnitType.Value) = {
    outputType match {
      case UnitType.fah => x: Double => x * 1.8 + 32
      case UnitType.kel => x: Double => x * 1.8 + 32
    }
  }

  def kelvin(outputType: UnitType.Value) = {
    outputType match {
      case UnitType.cel => x: Double => x - 273.5
      case UnitType.fah => x: Double => x * 1.8 + 32
    }
  }

  def fahrenheit(outputType: UnitType.Value) = {
    outputType match {
      case UnitType.cel => x: Double => x * 1.8 + 32
      case UnitType.fah => x: Double => x * 1.8 + 32
    }
  }

  println(convert(32.0, UnitType.cel, UnitType.fah))

}


推荐答案

我将执行以下操作:


  • 一个单位的枚举。

  • 每个单位都有一个 toKelvin 从开尔文方法开始。

  • 然后从单元 a 转换为单元 b 就是: b.fromKelvin(a.toKelvin())

  • 添加一个新单元只需要在新单元上实现这两种方法。

  • An enum of units.
  • Each unit has a toKelvin and from Kelvin method.
  • Then converting from unit a to unit b is just: b.fromKelvin(a.toKelvin())
  • Adding a new unit only requires implementing those two methods, on the new unit.

结果发现,在Scala中向Enumerations添加方法比Java要棘手,所以这是一个单例实现特征的实现:

Turns out adding methods to Enumerations is trickier in Scala than Java, so here's an implementation with singletons implementing a trait:

trait TemperatureUnit {
  def toKelvin(value : Double): Double
  def fromKelvin(value : Double): Double
  def convert(value : Double, unit : TemperatureUnit) : Double = fromKelvin(unit.toKelvin(value))
}

object Kelvin extends TemperatureUnit {
  def toKelvin(value : Double) = value
  def fromKelvin(value : Double) = value
}

object Celsius extends TemperatureUnit {
  def toKelvin(value : Double) = value + 273.5
  def fromKelvin(value : Double) = value - 273.5
}

然后将开尔文转换为摄氏就是

Then converting Kelvin to Celsius is just:

scala> Celsius.convert(100,Kelvin)
res0: Double = -173.5

您可能应该还要添加一个包装器类,这样您就不会传递空的 Double (可能会在没有编译器警告的情况下意外地用作长度,时间戳等)。

You should probably also add a wrapper class so that you're not passing around bare Doubles (which can accidentally be used as lengths, timestamps, etc. without a compiler warning).

class Temperature (value: Double, unit: TemperatureUnit) {
  def to(new_unit: TemperatureUnit) = new Temperature(new_unit.convert(value,unit),new_unit)
}

然后在您编写时

new Temperature(10,Celsius).to(Kelvin)

没有歧义。

这篇关于实现策略模式的功能方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆