JS++|接口

正如我们在子类型多态性一章中了解到的,为超类型定义的操作可以安全地用其子类型替换。因此,为“动物”对象定义的操作可以安全地接受“猫”或“狗”对象。

null

此外,我们提到,您不应该混淆子类型和继承。子类型描述类型之间的关系,而继承则与实现有关。这种区别在接口中变得很明显。

接口与我们刚刚了解的抽象类和方法类似,只是接口的所有“方法”都是抽象的。接口不包含任何实现。

接口指定类型,但不指定实现。让我们做一个交通类比。你需要从旧金山到洛杉矶。你可能不在乎如何到达那里,你只需要一种交通方式。接口不定义“方式”,因此在本例中,接口将是“运输方式”“如何”将在“火车”、“汽车”、“飞机”或“公共汽车”等课程中实施。只要“交通方式”可以移动,就应该满足你的需求。然而,你不能乘坐抽象的“交通方式”你需要一辆“汽车”、“火车”、“飞机”或“公共汽车”。

要可视化这些关系:

interface IModeOfTransport
{
    void move();
}

class Car : IModeOfTransport
{
    override void move() {
        // ...
    }
}

class Train : IModeOfTransport
{
    override void move() {
        // ...
    }
}

class Airplane : IModeOfTransport
{
    override void move() {
        // ...
    }
}

class Bus : IModeOfTransport
{
    override void move() {
        // ...
    }
}

每个具体类的动作都不同。例如,“汽车”的“移动”方法的实现与“飞机”截然不同,因为飞机可以飞行。

从这些关系中,您应该能够理解您可以实例化上面的一个类,例如“Car”,如下所示:

Car rentalCar = new Car();

假设你正在开发一个旅游网站。你想给用户提供从旧金山到洛杉矶的几种选择。在这种情况下,您可能希望概括该类型:

IModeOfTransport transport = new Car();

现在,当用户选择一个不同的选项(而不是“Car”)时,您可以轻松地将“transport”变量中保存的数据类型更改为“Train”、“Plane”或“Bus”的实例。

然而,你也认识到你不能通过“交通方式”从旧金山到洛杉矶。你必须指定哪种交通方式。因此,您应该认识到这将导致编译器错误:

IModeOfTransport transport = new IModeOfTransport();

因此,我们只使用接口来指定类型和类型关系。接口不提供实现,因此无法实例化。

有了这种理解,我们就能改变我们的“动物”型关系。首先,让我们从一个非常基本的例子开始。我们的一些动物没有颜色。现在只是一个黑白网页。让我们加点颜色。

导航到OOP项目中包含动物的“src/Animals/”文件夹。杰斯普,猫。杰普,狗。jspp等。在这个文件夹中,创建一个名为IColorizable的新文件。jspp。里面可以用肖像画。jspp,让我们输入以下代码:

module Animals
{
    interface IColorizable
    {
        void colorize();
    }
}

您会注意到的第一件事是,我们在接口名称前面加了“I”(大写字母“I”)。这被称为 命名约定 .命名约定帮助我们命名类、接口、模块、函数和变量,这些名称将与加入我们团队的其他程序员、其他第三方库等使用的名称一致。“I”是接口中的“I”,前缀为“it+”。

注意,我们不需要“抽象”修饰符。接口内的所有方法签名都被认为是抽象的,因为接口内不允许实现。

接下来,我们必须指定哪些类与IColorizable共享关系。现在,让我们只给“狗”类一些颜色:

import Externals.DOM;

external $;

module Animals
{
    class Dog : Animal, IColorizable
    {
        string _name;

        Dog(string name) {
            super("icofont-animal-dog");
            _name = name;
        }

        final void render() {
            $element.attr("title", _name);
            super.render();
        }

        final void talk() {
            alert("Woof!");
        }

        final void colorize() {
            $element.css("color", "brown");
        }
    }
}

现在,我们必须在“Dog”实例上调用colorize()方法。编辑主页。jspp:

import Animals;

external $;

IColorizable fido = new Dog("Fido");
fido.colorize();

Animal[] animals = [
    new Cat("Kitty"),
    new Cat("Kat"),
    fido, 
    new Panda(),
    new Rhino()
];

foreach(Animal animal in animals) {
    animal.render();
}

$("#content").append("<p>Number of animals: " + Animal.getCount().toString() + "</p>");

试着编译。您将得到一个错误:

[  ERROR  ] JSPPE5034: Could not determine type for array literal. All elements in array literal must be the same, a mixture of primitive types, or descendants of the same base class at line 8 char 19 at main.jspp

发生这种情况的原因是因为’fido’变量的类型为’IColorizable’。同时,数组只接受“Animal”类型的元素。如果您还记得,我们的“Dog”类直接继承自“IColorizable”,而“Animal”基类则没有继承。因此,我们不能将“IColorizable”的对象直接插入到“Animal”类型的数组中;否则,我们将能够执行JavaScript中的不安全操作。

图片[1]-JS++|接口-yiteyi-C++库

请注意,在图表中,“Animal”和“IColorizable”之间没有类型关系。

有多种方法可以解决这个问题。我们将通过使所有的动物都可以着色来解决这个问题。编辑狗。jspp并删除与“IColorizable”的类型关系。但是,将方法实现保留为“colorize”。稍后你会明白原因的。这里是一个可视化的东西,你必须删除在狗。jspp:

import Externals.DOM;

external $;

module Animals
{
    class Dog : Animal, IColorizable
    {
        string _name;

        Dog(string name) {
            super("icofont-animal-dog");
            _name = name;
        }

        final void render() {
            $element.attr("title", _name);
            super.render();
        }

        final void talk() {
            alert("Woof!");
        }

        final void colorize() {
            $element.css("color", "brown");
        }
    }
}

现在打开动物。jspp并添加:

external $;

module Animals
{
    abstract class Animal : IColorizable
    {
        protected var $element;
        private static unsigned int count = 0;

        protected Animal(string iconClassName) {
            string elementHTML = makeElementHTML(iconClassName);
            $element = $(elementHTML);

            attachEvents();

            Animal.count++;
        }

        public static unsigned int getCount() {
            return Animal.count;
        }

        public virtual void render() {
            $("#content").append($element);
        }

        public abstract void colorize();

        public abstract void talk();
        private void attachEvents() {
            $element.click(talk);
        }

        private string makeElementHTML(string iconClassName) {
            string result = '<div class="animal">';
            result += '<i class="icofont ' + iconClassName + '"></i>';
            result += "</div>";
            return result;
        }
    }
}

因为我们的“动物”类是“抽象的”,所以我们不需要“实现”这个“着色”方法。相反,我们只是将“colorize”方法声明为“abstract”,从而将其进一步推迟到“Animal”的派生类。还记得我们没有从“Dog”类中删除“colorize”方法吗?这就是为什么。我们已经将实现“colorize”的责任委托给了“Animal”的派生类,但我们仍然能够描述“Animal”和“IColorizable”之间的类型关系,其中“IColorizable”是“Animal”的超类型。

现在,我们只需要给其他动物添加颜色。我会保持简短。下面是一个模板,用于说明需要添加到“Cat”中的代码类型。jspp,熊猫。jspp和Rhino。jspp’:

final void colorize() {
    $element.css("color", colorName);
}

将“colorName”替换为要制作动物的颜色。让你的猫“金”,熊猫“黑”,犀牛“银”。

编辑主页。jspp:

import Animals;

external $;

Animal[] animals = [
    new Cat("Kitty"),
    new Cat("Kat"),
    new Dog("Fido"), 
    new Panda(),
    new Rhino()
];

foreach(Animal animal in animals) {
    animal.colorize();
    animal.render();
}

$("#content").append("<p>Number of animals: " + Animal.getCount().toString() + "</p>");

编译:

$ js++ src/ -o build/app.jspp.js

开放索引。html。结果应该是这样的:

图片[2]-JS++|接口-yiteyi-C++库

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享