2015-03-22 5 views
4

Я пытаюсь решить проблему, которая обрабатывает преобразование из одной единицы температуры в другую (Цельсия, Кельвина, Фаренгейта).Функциональный способ реализации стратегического шаблона

В Java Мне нужно создать интерфейс и предоставить несколько реализаций, которые инкапсулируют тип ввода и возвращают результат как единицу типа вывода. например, Кельвина до Цельсия или Цельсия до Фаренгейта и т. д. Я переработал свой код в scala до следующего, но все же я чувствую, что он нарушает принцип открытого закрытого типа, поскольку в случае, если мне нужно добавить другой тип, мне нужно изменить существующий код. сохранить код функциональной, а также приверженцем ОТКРЫТО зАКРЫТО принцип Просьба игнорировать логику для преобразования

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

} 

ответ

5

Я хотел бы сделать следующее:

  • перечисление единиц.
  • У каждого устройства есть метод toKelvin и from Kelvin.
  • Тогда преобразование из блока a к блоку b просто: b.fromKelvin(a.toKelvin())
  • Добавление нового блока требует только реализации этих двух методов, на новом устройстве.

Оказывается, добавив методы Перечисления сложнее в Scala, чем 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 
} 

Тогда преобразования Кельвина в градусы Цельсия просто:

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

Возможно, вы также должны добавить класс-оболочку, чтобы вы не проходили мимо голых Double s (которые могут случайно использоваться как длины, временные метки и т. Д. Без предупреждения компилятора).

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) 

Там не осталось двусмысленности.

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, нет необходимости изобретать новые способы.

Смежные вопросы