2015-02-12 3 views
0

У меня есть черта, которая определяет функцию - я не хочу указывать, как она будет работать дольше. Эта черта смешивается с несколькими классами случае, как так:Использование классов значений в scala для реализации методов признаков?

trait AnItem 
trait DataFormatable { 
    def render():String = "" // dummy implementation 
} 
case class Person(name:String, age:Int) extends DataFormatable with AnItem 
case class Building(numFloors:Int) extends DataFormatable with AnItem 

Итак, теперь я хочу includable модули, которые сутенер конкретные реализации этого поведения визуализации. Попытка использовать классы значений здесь:

object JSON { 
    implicit class PersonRender(val p:Person) extends AnyVal { 
    def render():String = { 
     //render json 
    } 
    } 
    // others 
} 

object XML { 
    implicit class PersonRender(val p:Person) extends AnyVal { 
    def render():String = { 
     //render xml 
    } 
    } 
    // others 
} 

Идеальное использование будет выглядеть следующим образом (предполагая выход JSON желаемому):

import JSON._ 
val p:AnItem = Person("John",24) 
println(p.render()) 

Все круто - но он не работает. Есть ли способ, с помощью которого можно работать с этой загружаемой реализацией? Я близко?

ответ

0

Характеристика DataFormatable здесь ничего не делает, кроме как сдерживать вас. Вы должны просто избавиться от него. Поскольку вы хотите поменять render реализаций на основе наличия имплицитов в области, Personне может есть свой собственный render метод. Компилятор будет искать неявное преобразование в PersonRender, если Person не имеет метода с именем render. Но поскольку Person наследует (или вынужден реализовать) render от DataFormatable, нет необходимости искать неявное преобразование.

На основании вашего редактирования, если у вас есть коллекция List[AnItem], также невозможно неявно преобразовать элементы в render. Хотя каждый из подклассов может иметь неявное преобразование, которое дает им render, компилятор не знает, что, когда все они сгруппированы в список более абстрактного типа. Особенно пустая черта, такая как AnItem.

Как вы можете это сделать? У вас есть два простых варианта.

Если вы хотите придерживаться неявных преобразований, вам необходимо удалить DataFormatable как супертип ваших классов case, чтобы у них не было собственного метода render. Затем вы можете поменять местами XML._ и JSON._, и конверсии должны работать. Однако вам не будут допущены смешанные коллекции.

Два, падение implicits в целом и есть ваша черта выглядеть следующим образом:

trait DataFormatable { 
    def toXML: String 
    def toJSON: String 
} 

Таким образом, вы вынуждаете каждый класс, который смешивает в DataFormatable содержать информацию сериализации (что так оно и должно быть, а чем скрывать их в неведении). Теперь, когда у вас есть List[DataFormatable], вы можете доказать, что все элементы могут быть преобразованы в JSON или XML, поэтому вы можете конвертировать смешанный список. Я думаю, что это будет намного лучше, поскольку код должен быть более простым. Какой импорт, который у вас есть, не должен действительно определять поведение следующего. Представьте себе путаницу, которая может возникнуть из-за того, что XML._ был импортирован в верхнюю часть файла вместо JSON._.

+0

Я думаю, что получаю это. Поэтому я обновил свой пример. Что делать, если у меня есть набор объектов (признаков) с различными реализациями (скажем, список AnItem выше), и я хотел бы отображать их как JSON или XML в зависимости. Если ни один из них не реализует render(), то, работая над признаком (AnItem) в modded примере, каким образом компилятор найдет render()? – Greg

+0

Он не может быть основан на информации типа 'AnItem'.Либо компилятор должен знать, что у вас есть «Личность», чтобы он мог найти правильное неявное, либо «Лицо» (и другие типы), возможно, должны реализовывать такие методы, как «toJSON» и «toXML» из общего признака. Это зависит от того, каким образом вы хотите идти. –

+0

@Greg См. Мое редактирование. –

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