2017-09-26 42 views
1

我需要根據傳遞的泛型選擇一個對象實現。這裏是我想要的一個小例子如何在運行時選擇一個對象 - Scala

import scala.reflect.runtime.universe.{TypeTag,typeOf} 


trait Animal27 
{ 
    val name: String 
    val sound: String 
} 


case class Tiger27(name:String, sound: String) extends Animal27 


object Tiger27 
{ 
def AbilityEvolve(tiger27 : Tiger27) : String = 
{ 
    tiger27.name + " is a tigher and she has increased attack" 
} 
} 


case class Cheetah27(name:String,sound:String) extends Animal27 

object Cheetah27 
{ 
    def AbilityEvolve(cheetah27: Cheetah27): String = 
    { 
    cheetah27.name + "is a cheethah and he has increased speed" 
    } 
} 



class World[A: TypeTag] { 

    def getMyObject = 
    { 
    if (typeOf[A] =:= typeOf[Cheetah27]) 
     Cheetah27 
    else 
     Tiger27 
    } 


    def Evolve : String = 
    { 
    getMyObject.AbilityEvolve + " hence evolved" // how do i perform 
                        //getMyObject.AbilityEvolve 
    } 
} 

object App27 extends App{ 
    val world = new World[Cheetah27] 
    println(world.Evolve) 
} 

我可以知道如何動態選擇基於所用通用對象。那麼如何確保getMyObject.AbilityEvolve能夠調用相應對象的方法?

感謝

回答

2

理想的解決方案將是使所有可能的返回類型的一些共同特徵繼承。因此,如果您需要在FirstObjectSecondObject之間進行選擇,它們都有foo方法,請定義一個HasFoo特徵,並將這兩個對象混合在該特徵中。

trait HasFoo { 
    def foo(): Unit 
} 

object FirstObject extends HasFoo { 
    def foo() = { println("FirstObject") } 
} 

object SecondObject extends HasFoo { 
    def foo() = { println("SecondObject") } 
} 

object WithTraits { 

    def decideAtRuntime(x: Boolean): HasFoo = 
    if (x) FirstObject else SecondObject 

} 

這樣做的好處是它的效率很高。 JVM運行時是爲了做這樣的多態而構建的,讀者也很清楚。如果您無法控制正在返回的對象,則始終可以使用implicits來添加對新特徵的支持。

但是,也許您的返回類型太籠統了,或者還有其他一些可以減輕情緒的情況。那樣的話,還有另外一種方法。 Scala支持所謂的結構類型。也就是說,您可以定義一個類型(而不是一個類;這是一個區別),其中包含所有具有foo方法的對象。

object FirstObject { 
    def foo() = { println("FirstObject") } 
} 

object SecondObject { 
    def foo() = { println("SecondObject") } 
} 

object WithStructure { 

    def decideAtRuntime(x: Boolean): { def foo(): Unit } = 
    if (x) FirstObject else SecondObject 

} 

請注意返回類型decideAtRuntime。這不是課程名稱,而是{ def foo(): Unit }。這是任何具有方法foo的對象的結構類型,它接受零參數並且不返回任何內容。

結構類型仍然是類型安全的,因爲Scala的編譯器會驗證這些方法確實存在於編譯時。但是,它會編譯到使用類和反射的JVM指令。這意味着如果Java API嘗試與它進行交互,那麼Java API可能不是類型安全的。這也意味着,由於反射API的工作方式,每次調用decideAtRuntime都會減慢程序運行速度。

+0

如果我希望foo()返回相應的對象/修改的對象,這看起來如何?謝謝。 – BigDataScholar

相關問題