2012-10-26 48 views
2

我有以下設計問題:與相關的特徵和依賴的實現設計問題

/** 
* Those 2 traits are the public API 
*/ 
trait Box { 
    def include(t: Token): Box 
} 
trait Token 

/** 
* Implementation classes 
*/ 
case class BoxImpl(id: Int) extends Box { 
    /** 
    * the implementation of this method depends on the implementation 
    * of the Token trait 
    * TODO: REMOVE asInstanceOf 
    */ 
    def include(t: Token) = BoxImpl(t.asInstanceOf[TokenImpl].id + id) 
} 
case class TokenImpl(id: Int) extends Token 

// use case 
val b: Box = new BoxImpl(3) 
val o: Token = new TokenImpl(4) 

// == BoxImpl(7) 
b.include(o) 

在上面的代碼,我不想公開API中暴露id(甚至沒有將其設置爲private[myproject]因爲這仍然會在我的項目中包含循環依賴項)。

當實現類彼此具有一定的可見性(沒有醜陋的表演)時,將保持公共API完好無損的方法是什麼?

回答

5

類型PARAM或構件:

trait Box { 
    type T <: Token 
    def include(t: T): Box 
    //def include(t: Token): Box 
} 
trait Token 

case class BoxImpl(id: Int) extends Box { 
    type T = TokenImpl 
    def include(t: T) = BoxImpl(t.id + id) 

    /* 
    def include(t: Token) = t match { 
    case ti: TokenImpl => BoxImpl(ti.id + id) 
    case _ => throw new UnsupportedOperationException 
    } 
    */ 

    //def include(t: Token) = BoxImpl(t.asInstanceOf[TokenImpl].id + id) 
} 
case class TokenImpl(id: Int) extends Token 

有很多方法來切割它,因此餅圖案,衆所周知的一塊蛋糕:

trait Boxer { 
    type Token <: Tokenable 
    trait Box { 
    def include(t: Token): Box 
    } 
    trait Tokenable 
} 

trait Boxed extends Boxer { 
    type Token = TokenImpl 
    case class BoxImpl(id: Int) extends Box { 
    override def include(t: Token) = BoxImpl(t.id + id) 
    } 
    case class TokenImpl(id: Int) extends Tokenable 
} 

trait User { this: Boxer => 
    def use(b: Box, t: Token): Box = b.include(t) 
} 

object Test extends App with Boxed with User { 
    val b: Box = new BoxImpl(3) 
    val o: Token = new TokenImpl(4) 
    println(use(b, o)) 
} 
+0

我加一個用例示出了API的用戶只能訪問公共特徵「Box」和「Token」。用你的代碼,我得到一個編譯錯誤:error:type mismatch; found:o.type(with underlying type test.Token) required:b.T ^ – Eric

+0

我想過要走這個方向,這當然是真正的「斯卡拉」方式。我看到的唯一缺點是所有的用戶代碼都必須在「Matrix內部」('this:Boxer'約束)中生存,這在API方面可能有點不同尋常。但是,正確的答案! – Eric