EDIT-将答案分为3个要点:初始编译错误的解决方案、递归解决方案和参数化解决方案
编译错误的解决
请注意,您的代码在顶层运行良好:
# let s = new salesman ();;
val s : < visitSalesman : 'a -> unit; _.. > salesman as 'a = <obj>
这种编译错误通常通过添加类型注释来帮助编译器计算类型来解决。正如顶层友好地告诉我们的那样,我们可以修改实例化:
let s : (< visitSalesman : 'a -> unit>) salesman = new salesman ();;
递归解
通过使用递归类可以降低复杂性。这完全消除了对参数化类的需求,但意味着所有对象都需要在同一个源文件中定义。
class virtual employee =
object
method virtual receiveEvaluation:(hrrep -> unit)
end
and accountant =
object(self)
inherit employee
method receiveEvaluation:(hrrep -> unit) = fun rep -> rep#visitAccountant (self :> accountant)
end
and salesman =
object (self)
inherit employee
method receiveEvaluation:(hrrep -> unit) = fun rep -> rep#visitSalesman (self :> salesman)
end
and hrrep =
object
method visitSalesman:(salesman -> unit) = fun s -> print_endline ("Visiting salesman")
method visitAccountant:(accountant -> unit) = fun s -> print_endline ("Visiting accountant")
end
let s = new salesman;;
let e = (s :> employee);;
let v = new hrrep;;
e#receiveEvaluation v;;
这上面印着“拜访推销员”。对员工的胁迫只是为了让这更接近现实世界的情况。
参数化解
class virtual ['a] employee =
object
method virtual receiveEvaluation : 'a -> unit
method virtual getName : string
end
class ['a] accountant name =
object(self)
inherit ['a] employee
val name = name
method receiveEvaluation rep = rep#visitAccountant self
method getName = "A " ^ name
end
class ['a] salesman name =
object(self)
inherit ['a] employee
val name = name
method receiveEvaluation rep = rep#visitSalesman self
method getName = "S " ^ name
end
class virtual hrRep =
object
method virtual visitAccountant : hrRep accountant -> unit
method virtual visitSalesman : hrRep salesman -> unit
end
class lowerLevelHRRep =
object
inherit hrRep
method visitAccountant a = print_endline ("Visiting accountant " ^ a#getName)
method visitSalesman s = print_endline ("Visiting salesman " ^ s#getName)
end;;
let bob = new salesman "Bob";;
let mary = new accountant "Mary";;
let sue = new salesman "Sue";;
let h = new lowerLevelHRRep;;
bob#receiveEvaluation h;;
mary#receiveEvaluation h;;
sue#receiveEvaluation h;;
这将返回:
拜访推销员S Bob
拜访会计师A Mary
拜访推销员S Sue
这种解决方案的优点是,员工不需要知道访问者,因此可以在自己的编译单元中定义,从而在添加新类型的员工时可以更清晰地编写代码,减少重新编译的工作量。