实施战略模式的功能方式

时间:2015-03-22 14:08:16

标签: scala design-patterns

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

在Java中,我需要创建一个接口并提供多个实现,这些实现封装了Input Type并将结果作为输出类型的单元返回。例如Kelvin到摄氏或摄氏到华氏等我已经在scala中重构了我的代码以下但仍然觉得它违反了Open封闭原则,因为如果我需要添加另一种类型我需要更改现有代码。任何建议保持代码功能以及遵守开放封闭原则 请忽略转换逻辑

    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))

}

2 个答案:

答案 0 :(得分:5)

我会做以下事情:

  • 单位枚举。
  • 每个单元都有toKelvinfrom Kelvin方法。
  • 然后从单位a转换为单位b只是:b.fromKelvin(a.toKelvin())
  • 添加新单元只需要在新单元上实现这两种方法。

在Scala中添加Enumerations的方法比Java更复杂,所以这里是一个实现特征的单例的实现:

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
}

然后将Kelvin转换为Celsius只是:

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

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

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)

没有任何含糊之处。

答案 1 :(得分:2)

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)
    }
  }

这不是一种策略模式。策略模式使用多态来处理不同的情况。 Scala不是纯粹的功能,它也是面向对象的,所以你可以像java一样实现策略模式,没有必要发明新的方法。