📜  JS++ |虚拟方法

📅  最后修改于: 2022-05-13 01:55:33.111000             🧑  作者: Mango

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'循环内)。