2017-09-22 24 views
0

這是一個「現實生活」的OO設計問題。我正在與Scala合作,並對特定的Scala解決方案感興趣,但我絕對樂於聽到類似的想法。如果方法沒有完全相同的簽名,如何設計抽象類?

我正在實施分支定界組合優化程序。算法本身很容易實現。對於每一個不同的問題,我們只需要實現一個類,其中包含有關搜索允許的鄰居狀態的信息,如何計算成本,然後可能是什麼下限等...

我也希望能夠嘗試不同的數據結構。例如,存儲邏輯公式的一種方法是使用一個簡單的整數列表列表。這表示一組子句,每個整數都是文字。我們可以有更好的表現,儘管如果我們做一些像「雙字面觀察名單」這樣的東西,並且通常會存儲關於公式的額外信息。

這一切都將意味着像這樣

object BnBSolver[S<:BnBState]{ 
    def solve(states: Seq[S], best_state:Option[S]): Option[S] = if (states.isEmpty) best_state else 
    val next_state = states.head 
    /* compare to best state, etc... */ 
    val new_states = new_branches ++ states.tail 
    solve(new_states, new_best_state) 
} 

class BnBState[F<:Formula](clauses:F, assigned_variables) { 
    def cost: Int 

    def branches: Seq[BnBState] = { 
    val ll = clauses.pick_variable 
    List(
     BnBState(clauses.assign(ll), ll :: assigned_variables), 
     BnBState(clauses.assign(-ll), -ll :: assigned_variables) 
    ) 
    } 
} 

case class Formula[F<:Formula[F]](clauses:List[List[Int]]) { 
    def assign(ll: Int) :F = 
     Formula(clauses.filterNot(_ contains ll) 
         .map(_.filterNot(_==-ll)))) 

} 

但願這不是太瘋狂了,錯誤或混淆。這裏的整個問題是,這個公式的這個assign方法通常只會使用將要分配的當前文字。然而,在兩個字面的觀察列表中,你正在做一些懶惰的事情,需要你稍後知道以前分配了哪些文字。

解決此問題的一種方法是,您只需將以前分配的文字列表保留在數據結構中,也許作爲私人事物。使其成爲獨立的懶惰數據結構。但是,以前任務的列表實際上是任何使用Formula類的人都可以使用的。因此,如果有必要,允許使用它的人每次只在assign時提供列表。

這裏的問題是,我們現在不能有一個摘要Formula類,只是聲明assign(ll:Int):Formula。在正常情況下,這是好的,但如果這是一個雙字面觀察列表公式,它實際上是一個assign(literal: Int, previous_assignments: Seq[Int])

從使用它的類的角度來看,它是好的。但是,我們如何編寫通用代碼,可以使用所有這些不同版本的Formula?由於簽名的劇烈變化,它不能簡單地成爲抽象方法。我們可以強迫用戶總是提供完整的分配變量,但這也是一種謊言。該怎麼辦?

這個想法是觀察列表類只是成爲一種常規assign(Int)類,如果我寫下某種適配器方法,知道從哪裏採取以前的任務...我想也許用implicit我們可以做點什麼向上。

+0

我發現你的問題,因爲它有點混亂。我的感覺是,你正在混淆你的算法的許多擔憂(再次)對Scala的太多關注。 – pedrofurla

+0

公式是否帶有類型參數? – pedrofurla

+0

順便解決不會編譯。 – pedrofurla

回答

3

我會盡量讓自己的回答有點泛泛,因爲我不確定我是完全是下面是你正在做的事情。無論如何...

通常,第一個想法應該是接受一個共同的超類作爲參數。很明顯,這不適用於IntSeq[Int]

你可能只有兩種方法;有一個呼叫另一個。例如,只需將一個Int換成Seq[Int]並將其傳遞給另一個方法即可。

您也可以在某些自定義類中包裝參數,例如

class Assignment { 
    ... 
} 
def int2Assignment(n: Int): Assignment = ... 
def seq2Assignment(s: Seq[Int]): Assignment = ... 
case class Formula[F<:Formula[F]](clauses:List[List[Int]]) { 
    def assign(ll: Assignment) :F = ... 
} 

當然,你將不得不作出的轉換方法隱,使主叫方只需要導入他們,而不是顯式調用的選項。

最後,你可以用一個類型類做到這一點:

trait Assigner[A] { 
    ... 
} 
implicit val intAssigner = new Assigner[Int] { 
    ... 
} 
implicit val seqAssigner = new Assigner[Seq[Int]] { 
    ... 
} 
case class Formula[F<:Formula[F]](clauses:List[List[Int]]) { 
    def assign[A : Assigner](ll: A) :F = ... 
} 

你也能有這樣的類型參數在類級別:

以下哪一條路徑是最好的可達偏好以及它如何適應其他代碼。

相關問題