JS++ |虚拟方法
正如我们在上一节中提到的,如果我们想要运行时多态,使用强制转换会导致代码不干净。
例如,让我们更改 main.jspp 代码,以便我们所有的动物都在一个数组中。从那里,我们将遍历数组以渲染动物。打开 main.jspp 并将代码更改为:
import Animals;
Animal[] animals = [
new Cat("Kitty"),
new Cat("Kat"),
new Dog("Fido"),
new Panda(),
new Rhino()
];
foreach(Animal animal in animals) {
if (animal instanceof Cat) {
((Cat) animal).render();
}
else if (animal instanceof Dog) {
((Dog) animal).render();
}
else {
animal.render();
}
}
现在我们的代码甚至不如我们刚刚实例化动物、指定最具体的类型并调用 render() 的原始代码那么优雅。
然而,这段代码可以被大量简化,直到它变得优雅。事实上,我们可以将“foreach”循环缩减为一条语句。答案:虚拟方法。
虚拟方法支持“后期绑定”。换句话说,调用的具体方法是在运行时而不是编译时解析的。我们不需要我们在上面的代码中看到的所有“instanceof”检查、所有强制转换和所有“if”语句。我们可以实现更优雅的东西。
首先,打开 Animal.jspp 并更改 'render' 方法以包含 'virtual' 修饰符:
external $;
module Animals
{
class Animal
{
protected var $element;
protected Animal(string iconClassName) {
string elementHTML = makeElementHTML(iconClassName);
$element = $(elementHTML);
}
public virtual void render() {
$("#content").append($element);
}
private string makeElementHTML(string iconClassName) {
string result = '';
result += '';
result += "";
return result;
}
}
}
保存 Animal.jspp。这是我们唯一需要做的改变。
然而,仅仅使我们的方法虚拟化是不够的。在 Cat.jspp 和 Dog.jspp 中,我们在它们的 'render' 方法上使用了 'overwrite' 修饰符。 'overwrite' 修饰符指定编译时分辨率。我们想要运行时解析。我们所要做的就是将 Cat.jspp 和 Dog.jspp 更改为使用 'override' 修饰符而不是 'overwrite' 修饰符。为简洁起见,我将只显示对 Cat.jspp 的更改,但您还需要对 Dog.jspp 进行更改:
external $;
module Animals
{
class Cat : Animal
{
string _name;
Cat(string name) {
super("icofont-animal-cat");
_name = name;
}
override void render() {
$element.attr("title", _name);
super.render();
}
}
}
就是这样。我们所要做的就是更改修饰符。现在我们终于可以编辑 main.jspp 了,所以循环中只有一条语句:
import Animals;
Animal[] animals = [
new Cat("Kitty"),
new Cat("Kat"),
new Dog("Fido"),
new Panda(),
new Rhino()
];
foreach(Animal animal in animals) {
animal.render();
}
编译您的代码并打开 index.html。一切都应该工作。现在我们已经能够大大简化我们的代码并且仍然获得预期的行为。具体来说,我们将“foreach”循环的代码从:
foreach(Animal animal in animals) {
if (animal instanceof Cat) {
((Cat) animal).render();
}
else if (animal instanceof Dog) {
((Dog) animal).render();
}
else {
animal.render();
}
}
对此:
foreach(Animal animal in animals) {
animal.render();
}
我们能够如此显着地简化代码的原因是因为将方法标记为“虚拟”意味着潜在的运行时多态性。与 'override' 修饰符一起,编译器知道我们想要对 'render' 方法进行后期绑定,因此“后期”绑定恰好在需要时发生:'render' 方法将在运行时解析,当且仅当它需要时被解决(在'foreach'循环内)。