這很煩人,但實現您所需模式的解決方案並不是微不足道的。
第一點要注意的是,如果你想保留你的子類型,你需要添加一個類型參數。沒有這一點,你是不是能夠在HttpMessage指定一個未知的返回類型
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String):X
}
然後你就可以實現你的具體子類的方法,你必須指定X的值:
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers){
type X = HttpRequest
def addHeader(header: String):HttpRequest = new HttpRequest(path, headers :+header)
}
一個更好的,更具擴展性的解決方案是使用隱式的目的。
trait HeaderAdder[T<:HttpMessage]{
def addHeader(httpMessage:T, header:String):T
}
,現在你可以在HttpMessage類像下面的定義方法:
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String)(implicit headerAdder:HeaderAdder[X]):X = headerAdder.add(this,header) }
}
這個最新方法是基於類型類的概念和規模不是繼承好得多。這個想法是,您不必強制您的層次結構中的每個T都具有有效的HeaderAdder [T],並且如果您嘗試在範圍內沒有隱式可用的類上調用該方法,則會收到編譯時錯誤。
這很好,因爲它可以防止在層次結構中的某些類變爲「髒」或重構它以避免它變成時,必須實現addHeader = sys.error(「This is not supported」) 「髒」。
管理隱最好的辦法是把它們放在一個特點如下所示:
trait HeaderAdders {
implicit val httpRequestHeaderAdder:HeaderAdder[HttpRequest] = new HeaderAdder[HttpRequest] { ... }
implicit val httpRequestHeaderAdder:HeaderAdder[HttpWhat] = new HeaderAdder[HttpWhat] { ... }
}
,然後您還提供了一個對象,如果用戶如果有不能混用(如通過物體的反射性質研究框架,你不想額外的屬性添加到您當前的實例)(http://www.artima.com/scalazine/articles/selfless_trait_pattern.html)
object HeaderAdders extends HeaderAdders
因此,例如,你可以寫的東西,如
// mixing example
class MyTest extends HeaderAdders // who cares about having two extra value in the object
// import example
import HeaderAdders._
class MyDomainClass // implicits are in scope, but not mixed inside MyDomainClass, so reflection from Hiberante will still work correctly
順便說一句,這個設計問題是相同的斯卡拉集合,唯一的區別是你的HttpMessage是TraversableLike。看看這個問題Calling map on a parallel collection via a reference to an ancestor type
請問你能否完成這個例子或描述如何採取最後一步?你可以在Object HttpRequest中定義一個隱含的val HeaderAdder,是否正確?非常感謝 – LaloInDublin
嗨Edmondo1984,謝謝你的回覆!很高興知道我不只是錯過了一些明顯的東西:)雖然我沒有考慮過你提出的第二種選擇,我一定會嘗試一下。 – headexplodes