2012-05-02 160 views
1

,以確保協方差有三種方式實現的協方差:使用虛擬類型(抽象類型)

  1. 純協方差:使用艾菲爾語言,
  2. 模擬協方差:使用強制轉換和重載
  3. 使用F-界多態或虛擬類型

因此,我正在使用虛擬類型測試解決方案,使用scala抽象類型的示例如下:

  • 我們定義3抽象類:圖形,節點,邊緣
  • 圖形類定義2種方法:attachNode(節點)和detachNode(節點)
  • 節點類定義2種方法:attachToGraph(圖表)和detachFromGraph()

使用inheretence我們會爲不同的域創建不同的子類:

  • 對於網絡:class Network extends Graph,和class Host extends Node,..
  • 對於化學:class Molecule extends Graph,和class Atom extends Node,..
  • ...

的唯一的限制是,以避免產生 「嵌合體」,由例如附接原子與網絡。因此,該模型是比較簡單的:

abstract class Graph { 
    type CompatibleNode <: Node 
    protected var myNodes = new ArrayBuffer[CompatibleNode]() 

    def attachNode(node : compatibleNode) = { 
     .... 

     // Inform the node about the attachement so it can do update 
     node.attachToGraph(this) 

     // save the node 
     myNodes += node 
    } 
} 

abstract class Node { 
    type CompatibleGraph >: scala.Null <: Graph 
    protected var myGraph : CompatibleGraph = null 

    def attachToGraph(graph : compatibleGraph) = { 
     .... 

     // Inform the graph about the attachement so it can do update 
     graph.attachNode(this) 

     // save the node 
     myGraph = graph 
    } 
} 

及後創造我們剛剛覆蓋虛擬類型的特殊圖表:

class Network extends Graph { override type CompatibleNode = Host} 
class Host extends Node { override type CompatibleGraph = Network} 

class Molecule extends Graph { override type CompatibleNode = Atom} 
class Atom extends Node { override type CompatibleGraph = Molecule} 

這應該很好地工作(工作在NIT語言),但我有不同錯誤:調用graph.attachNode(this)

  • 首先,類型不匹配需要選用這種graph.CompatibleNode,發現:Graph,所以我投這樣的:

    graph.attachNode(this.asInstanceOf [graph.CompatibleNode])

注意,NIT語言做隱含蒙上。

  • 其次,在那之後的detachFromGraph()方法:

    類節點{

    ... 
    
    def detachFromGraph() = { 
    
        .... 
    
        // inform my graph 
        myGraph.detachNode(this.asInstanceOf[myGraph.CompatibleNode]) 
    
        ... 
    } 
    

    }

我得到了錯誤:myGraph.compatibleNode : requiered stable identifier,經過搜索和閱讀規範我發現: - >一個穩定的標識符是路徑wich en d帶有標識符 - >p.x是路徑,如果p是路徑並且x是穩定成員 →穩定成員是.....或非易失性類型的值定義 →易失性類型:類型參數或抽象類型,...

所以簡而言之,我不能在路徑中使用抽象類型的對象,爲什麼?我不知道!

所以如果有人有建議,或者即使有可能使用scala抽象類型作爲虛擬類型。

+0

我沒有看到艾菲爾如何「確保」協方差。它的處理協變性的方法甚至違反了利斯科夫替代原則,即使它們處於逆變位置也允許協變類型參數。 –

+0

我已閱讀[這個問題]的評論(http://stackoverflow.com/questions/5129943/tightly-coupled-parallel-class-hierarchies-in-c)(我有類似的問題),這是可能的在C++中實現其中的一些想法。有人知道如何? –

+0

你在說什麼樣的協方差?如果你能說出你的定義,也許它會有所幫助。目前你的定義是不健全的,因爲如果你調用'attachNode',你不能確保'this'與'Node'(和'attachToGraph'的vv兼容),因爲你的類型方案不需要/表達兼容性關係是對稱的。 – gzm0

回答

0

這裏的а解決方法:

def detachFromGraph() { 
     detachFromThisGraph (myGraph) 
    } 

    def detachFromThisGraph (graph : CompatibleGraph) { 
     graph.detachNode(this.asInstanceOf[graph.CompatibleNode]) 
    } 

我還沒有一個絲毫的想法穩定的標識符是什麼,或者爲什麼需要在這裏。

1

這可以工作(並消除無限循環)。該軟件包只是爲了說明軟件包的私有方法。

package foo { 
    abstract class Graph { 
    type CompatibleNode <: Node 
    protected var myNodes = new ArrayBuffer[CompatibleNode]() 

    def attachNode(node: CompatibleNode) 
        (implicit ev: this.type <:< node.CompatibleGraph) { 

     // Inform the node about the attachement so it can do update 
     node.backAttach(ev(this)) 

     // save the node 
     myNodes += node 
    } 

    private[foo] def backAttach(node: CompatibleNode) { myNodes += node } 
    } 

    abstract class Node { 
    type CompatibleGraph >: scala.Null <: Graph 
    protected var myGraph: CompatibleGraph = null 

    def attachToGraph(graph: CompatibleGraph) 
        (implicit ev: this.type <:< graph.CompatibleNode) { 

     // Inform the graph about the attachement so it can do update 
     graph.backAttach(ev(this)) 

     // save the node 
     myGraph = graph 
    } 

    private[foo] def backAttach(graph: CompatibleGraph) { myGraph = graph } 
    } 
} 

現在:

class Network extends foo.Graph { override type CompatibleNode = Host} 
class Host extends foo.Node { override type CompatibleGraph = Network} 

class Molecule extends foo.Graph { override type CompatibleNode = Atom} 
class Atom extends foo.Node { override type CompatibleGraph = Molecule} 

,並嘗試一下:

object GraphTest { 
    val n = new Network() 
    val h = new Host() 

    n.attachNode(h) 

    val a = new Atom() 

    n.attachNode(a) // fails: type mismatch; 
    // found : Atom required: GraphTest.n.CompatibleNode (which expands to) Host 
}