要确保协方差,有三种方法:
- 纯协方差:使用埃菲尔铁塔语言,
- 模拟协方差:使用强制转换和重载
- 使用 F 界策略态或虚拟类型
所以我正在使用虚拟类型测试解决方案,在以下示例中使用 scala 抽象类型:
- 我们定义了3个抽象类:图,节点,边
- Graph 类定义了 2 个方法:attachNode(Node( 和 detachNode(Node(
- Node 类定义了 2 个方法:attachToGraph(Graph( 和 detachFromGraph((
使用固有,我们将为不同的域创建不同的子类:
- 对于网络:
class Network extends Graph
和class Host extends Node
,.. - 化学:
class Molecule extends Graph
和class Atom extends Node
,.. - 。
唯一的约束是避免创建"嵌合体",例如将Atom连接到网络。所以模型比较简单:
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.兼容节点](
请注意,NIT 语言以隐式强制转换的方式执行。
其次,之后对于 detachFromGraph(( 方法:
类节点 {
... def detachFromGraph() = { .... // inform my graph myGraph.detachNode(this.asInstanceOf[myGraph.CompatibleNode]) ... }
}
我收到错误:myGraph.compatibleNode : requiered stable identifier
,在搜索和阅读规范后,我发现:-> 稳定的标识符是以标识符结尾的路径-> p.x
是路径,如果p
是路径并且 x
是稳定成员->稳定成员是.....或非易失性类型的值定义->易失性类型:类型参数或抽象类型,....
所以简而言之,我不能在路径中使用抽象类型的对象,为什么?我不知道!
所以如果有人有建议,或者即使可以使用Scala抽象类型作为虚拟类型。
这有效(并且也删除了无限循环(。该包只是为了能够说明包私有方法。
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
}
以下是解决方法:
def detachFromGraph () {
detachFromThisGraph (myGraph)
}
def detachFromThisGraph (graph : CompatibleGraph) {
graph.detachNode(this.asInstanceOf[graph.CompatibleNode])
}
我一点也不知道什么是稳定的标识符,或者为什么这里需要它。