‫在本课中, 您将通过一个具体的示例学习如何创建和实现您自己的接口,
‫并且您将了解为什么要使用接口, 尤其是当我们的类彼此之间没有关系,
‫因此它们不共享基类时｡
‫因此, 继承本身不是一种选择｡
‫想象一下, 我们正在开发一个视频游戏, 玩家可以破坏东西,
‫但是我们破坏的东西会根据被破坏的东西而有不同的行为｡
‫例如, 摧毁一把椅子将播放一些摧毁声音, 并将产生摧毁的椅子零件｡
‫但摧毁一辆汽车会播放爆炸声, 产生火灾, 并摧毁附近的其他物体｡
‫对于我们的游戏, 我们有以下类：继承自furniture类的chair和继承自vehicle类的car｡
‫让我们真实的地看一下这些类｡
‫所以我们有一把椅子, 它继承了家具,
‫椅子有一个简单的构造函数, 我们可以根据所创建对象的颜色和材质来设置它.
‫但是现在, 这个类继承了家具, 这就是为什么我们在这里有那些属性, 颜色和材质,
‫我们刚才在椅子类中使用了这些属性｡
‫这里有一个构造函数, 它是默认的构造函数, 默认情况下会在这里设置这些值.
‫因此, 默认情况下, 颜色和材质将为白色和木材｡
‫然后我们还有一个简单的构造函数, 它使用颜色和材质来默认设置它们｡
‫好吧, 没什么好幻想的, 但我们当然也有一辆车, 我们希望能够摧毁椅子和车,
‫就像我之前说的那样｡
‫让我们真实的看看这辆车｡
‫这里我们有同样的故事, 一个子类汽车, 它扩展了车辆, 我们设置了汽车的速度和颜色｡
‫所以现在我们使用的是, 一个简单的构造函数, 就像我们在这里做的那样｡
‫当然, 我们也可以在这里使用based, 传递速度和颜色｡
‫所以这也是一个有效的选项, 我们在这里不必使用它｡
‫当然, 有两种不同的方法来实现它｡
‫好吧, 我会的
‫这辆车继承了车辆的特性, 当然, 速度和颜色也是必须定义的｡
‫让我们看看车辆类, 我们可以看到, 这个基类车辆有速度,
‫颜色, 默认构造函数, 它设置了这两个值, 速度为120千米每小时, 颜色为白色.
‫然后我们有一个简单的构造函数, 它根据车辆对象的值来设置速度和颜色｡
‫当然, 也以汽车等继承对象为例｡
‫好吧, 我会的
‫现在我们已经有了所有这些不同的类, 并且了解了它们的结构, 让我们来看看实际的销毁特性.
‫那么, 创建这样一个破坏特性的最佳方法是什么呢？
‫如果我们考虑一下, 我们不能添加一个类, 让我们的类继承它,
‫因为C-sharp是一个单继承语言, 而不是一个多继承语言, 我们都已经从一个类继承了,
‫所以汽车已经从车辆继承了, 椅子已经从家具继承了｡
‫所以它不能从其他东西继承｡
‫比如说, 这里的车辆, 你看, C-sharp不允许这样做,
‫因为它不能有多个基类｡
‫在C-sharp中, 一个类不能有多个基类｡
‫所以, 再加上汽车和椅子之间没有具体的关系来共享一个基类, 因为它们是完全不同的两件事,
‫对吗？
‫如果我们实现了普通的方法, 比如说, 在我们这里的每个类中, 叫做destroy方法,
‫那么它将很难维护｡
‫如果我们决定完全改变破坏系统或者在未来给我们的可破坏物体增加视觉效果呢？
‫这将是一个痛苦, 实际上通过每个类和修改它｡
‫因为在这个例子中, 我们可以说只有两个子类｡
‫好吧, 我知道了
‫但是想象一下你有50个甚至100个不同的职业, 100个不同类型的对象在你的游戏中｡
‫然后, 您将不得不检查每一个, 并相应地调整代码｡
‫所以这真的是一个负担, 我们不想经历｡
‫这就是为什么我们需要找到一个更好的解决方案｡
‫我们需要的是一种方法来强制我们的分心行为对每一个类使用它, 就像一个合同｡
‫如果你看过我们关于界面的视频, 你就会知道它们是我们可以创造的契约｡
‫所以在这种情况下最好的方法是使用一个接口, 我们称之为I Destroy Able｡
‫而任何实现这个接口的类都将被迫遵循我们的销毁要求, 同时根据类本身来定制它｡
‫让我们继续创建这样一个接口｡
‫因此, 您可以在此处转到您的项目, 添加一个新项, 然后在此处选择interface并为其命名｡
‫所以我打算跟注｡
‫我会销毁ble, 这样你就可以看到, 当你使用接口的时候, 你在文件名的开头加上I,
‫来表示这是一个接口｡
‫所以让我们添加这个接口｡
‫所以这个接口只有一个属性来存储音频文件, 一旦我们执行销毁, 就会运行这个音频文件,
‫也就是销毁声音｡
‫然后我们就有了一个销毁对象的方法, 我们将这个方法命名为destroy.
‫它不会返回任何东西, 它只会破坏一些东西｡
‫例如, 它可以返回你所拥有的图形｡
‫因此, 您希望在项目被销毁后显示的对象, 例如,
‫汽车被销毁或椅子被销毁等｡
‫现在让我们确保我们的类实际上要实现这个接口, 然后, 当然要实现接口的内容,
‫也就是销毁声音和销毁方法.
‫我们如何才能做到这一点？
‫好了, 让我们看看我们的汽车, 比如, 这里我们的汽车需要在类定义的顶部添加一个逗号, 并使用这个I
‫destroy able接口, 就像现在这样, 如果你添加,
‫你可以看到你会得到一个错误, 它说汽车没有实现接口成员销毁声音以及销毁, 这样我们就可以显示潜在的修复程序,
‫并实现所有成员｡
‫例如, 这将为我们创建这个自动代码｡
‫所以它会创造出虚空, 毁灭, 能够毁灭, 它会为我们创造出毁灭的声音｡
‫这是自动生成的版本, 但我们也可以手动生成｡
‫这没问题｡
‫例如, 我们可以在这里实现破坏音｡
‫然后我希望能够做的是我希望有一个属性来存储附近被破坏的对象｡
‫所以当一辆车被摧毁时, 它也应该摧毁附近的物体｡
‫这个列表的类型也是｡
‫我销毁able, 这意味着它可以存储任何实现这个接口的对象,
‫我们只能访问那个接口中的属性和方法｡
‫为了创建这个, 我要创建一个公共列表, 我销毁所有对象,
‫我把它们叫做销毁球｡
‫所以现在我们可以继续扩展我们的构造函数｡
‫所以一方面, 我们要确保初始化声音｡
‫所以我们要确保有爆炸的声音｡
‫例如, 我们有一个声音, 叫做汽车爆炸声音放大器3｡
‫然后我们要初始化可销毁对象的列表｡
‫例如, 这将是一个新的已销毁对象列表, 然后我们还需要实现destroy方法｡
‫所以我要毁掉它｡
‫在顶部, 你可以看到它仍然不高兴, 它仍然希望我们实现destroy方法.
‫所以当你实现一个接口的时候, 你需要实现它的成员, 因为这里的接口有两个成员,
‫我们需要同时实现它们.
‫这意味着我们需要回到这里, 我们需要真正实现destroy方法.
‫所以让我们快速地做一下｡
‫我想在这里补充的是, 首先, 两个声明｡
‫我将使用右行语句｡
‫我会保持简单, 因为我们不是在这里创建一个游戏, 而是试图理解界面的概念｡
‫所以当一辆车被摧毁时, 我们应该播放毁灭的声音, 并创造一个火灾效果｡
‫所以我们只是在模仿, 就好像我们真的会播放声音, 它只会说, 好吧,
‫播放汽车爆炸放大器的三个声音, 然后我们创造了火｡
‫所以一切都在战火中｡
‫所有的东西都在燃烧, 因为车毁了｡
‫现在让我们来看看每一次销毁, 都是在附近的, 并实际销毁它｡
‫这里我们要检查一下, 我销毁的所有对象, 它们都在我们的销毁球列表中.
‫我们称之为毁灭一切｡
‫所以每一项都是一个被破坏的球, 基本上就是一个局部变量名.
‫所以我们说, 好的, 被销毁的对象, 它将实现ID可存储接口, 在我们的for each循环中,
‫它将被称为销毁球｡
‫所以我们遍历它, 也就是遍历集合,
‫销毁附近的球, 这是一个销毁对象的列表, 基本上是实现ID可扩展接口的对象,
‫然后我们调用销毁方法.
‫所以基本上我们在这里制造了一个连锁反应, 摧毁周围的一切一切被摧毁的一切, 也是一辆汽车等等｡
‫在这个例子中, 假设我们有两汽车并排而它们有一堆椅子.
‫所以汽车会调用这个销毁方法, 它们会销毁附近的物品, 因为这是一个巨大的爆炸｡
‫好吧, 我知道了
‫有一个声音来了, 每一个项目创建一个声音｡
‫当然, 你可以创建一个计时器, 它需要直到真正的爆炸发生后, 着火的东西｡
‫但我们要保持简单｡
‫所以我们要摧毁其他的汽车, 还有其他的椅子｡
‫所以每辆车都会感染周围的其他物品｡
‫这可能是, 比如说, 十米或五米外的任何东西, 或者如果你想在这里用美国的系统的话,
‫不管多少英寸远｡
‫但这基本上就是将要发生的事情｡
‫现在, 让我们来看看椅子, 因为椅子也要经过类似的方法,
‫因为我们也要确保椅子被销毁, 但椅子的销毁将是非常不同的｡
‫因此, 我们还将在此处添加接口｡
‫所以I销毁所有接口, 当然我们需要实现销毁声音,
‫这将是一个非常不同的销毁, 因为椅子会散架, 你会听到木头碎裂的声音｡
‫所以这里的声音会很不一样｡
‫当然, 我们还想在构造函数中定义破坏音｡
‫所以我要说应该播放椅子破坏音｡
‫它永远都是一样的｡
‫这就是为什么我不把它加在主席声明中｡
‫所以我在这里保持简单｡
‫当然, 你可以有不同的椅子, 有不同的爆炸声｡
‫然后将其添加到顶部作为构造函数的参数｡
‫好了, 现在让我们实际实现destroy方法｡
‫在这种情况下, 我们会破坏一些东西, 首先, 我们会根据椅子的颜色来破坏彩色椅子｡
‫我们会写下来, 然后播放毁灭的声音｡
‫最后, 我们将生成椅子部件｡
‫所以在我们的例子中, 我们只是把它写在控制台上｡
‫但是想象一下在真实的游戏中你会怎么做, 因为在电子游戏中破坏东西的最好方法不是真正做物理上的事情,
‫你做所有的破坏, 这是非常困难的, 特别是如果｡
‫没有一个大的团队, 做各种各样的事情｡
‫然后你基本上只需要制作一个大的爆炸或破坏动画, 然后你会产生周围各个部分的被破坏部分｡
‫所以你可以看到, 这种销毁方法没有产生连锁反应｡
‫所以椅子的destroy方法实现与车辆的destroy方法实现有很大不同, 但它们都继承自I
‫destroy able接口, 必须实现destroy方法, 而且它们可以按自己的方式来实现｡
‫所以基本上接口允许我们进行某种多重继承, 尽管它不是真正的多重继承｡
‫好吧, 我会的
‫现在让我们继续我们的程序, CSS, 实际上使用我们新创建的类, 因为否则它很无聊, 对吗？
‫让我们继续创建两把椅子｡
‫我们有一把棕色的塑料办公椅, 还有一把红色的木质游戏椅｡
‫然后让我们也创造一辆新车｡
‫所以这辆车的速度会是80, 它会是蓝色的, 它会是一辆损坏的车｡
‫然后我们再加上旁边的两把椅子, 这辆损坏的车｡
‫因此, 我们将它们作为损坏的车轮添加到损坏的汽车附近｡
‫所以办公椅和游戏椅现在是, 如果我们看它被破坏了, 它就在附近, 因为当创建汽车时,
‫这个列表是空的.
‫当然, 我们可以这样做, 因为这是一个公共列表, 我们可以向其中添加项目, 我们这样做了｡
‫我们把所有被摧毁的物品都加到里面｡
‫为什么我们可以在附近给我们被摧毁的球加椅子呢？
‫嗯, 因为椅子实现了这个接口｡
‫我们称之为部落｡
‫这意味着一把椅子现在将被接受为类型I销毁的对象｡
‫也就是说我们现在可以把它作为附近的干扰｡
‫所以现在我们可以继续摧毁这辆车了｡
‫所以我们只调用损坏汽车的destroy方法, 这样爆炸就可以参与进来｡
‫爆炸声可以开始和所有的好东西｡
‫那我们开始吧｡
‫当然, 这将更多的是一个冒险游戏, 而不是一个游戏, 你看到实际的三维图形或任何东西｡
‫所以我们播放破坏声音, 汽车爆炸的声音, 我们制造火灾｡
‫棕色的椅子被毁了｡
‫我们正在播放椅子破坏音三号放大器的破坏音｡
‫然后, 我们将为棕色椅子生成椅子部件｡
‫然后红色的椅子被摧毁了｡
‫我们正在播放椅子破坏声音放大器3的破坏声音, 然后我们正在为我们的红色椅子繁殖椅子部件｡
‫所以你看, 差不多就是这样｡
‫这就是你如何创建你自己的界面, 以及如何使用它们｡
‫我希望您现在已经了解了接口可以为您做些什么以及接口的优势｡
‫所以这里需要注意的是, 接口用于两个相似或不相似的类之间的通信,
‫这些类不关心实现接口的类的类型｡
‫就像我们的汽车如何与椅子通信以调用destroy方法一样, 这一切都是因为它们实现了我前面提到的相同接口｡
‫因此, 尽管界面乍一看似乎很难理解, 但它们为我们提供了很大的好处｡
‫这些好处就是代码可读性｡
‫所以一个接口构成了一个关于意图的声明, 所以它定义了类的功能｡
‫所以你的类能够做什么, 例如, 如果你实现了AI sortable,
‫你就清楚地声明了你的类的对象可以被排序, 然后代码语义｡
‫通过提供接口并实现它们, 您可以主动地分离概念,
‫接口定义了一个行为模型, 一个对象可以做什么的定义, 分离这些概念可以使代码的语义更加清晰｡
‫然后你就有了密码｡
‫可维护性接口有助于减少耦合, 并允许您轻松地交换相同概念的实现,
‫而不会影响底层代码｡
‫然后是设计模式｡
‫这是一个更大的图景, 使用契约､ 抽象和面向对象编程的关键接口,
‫因此人类的理解和复杂的系统架构｡
‫所以这基本上只是为了更好地理解它作为一个人, 然后多重继承｡
‫因此, 接口可以成为我们在C-sharp中使用多重继承的途径｡
‫因此, 假设您编写了一个库, 并希望它可以由用户修改｡
‫您编写接口及其类实现｡
‫将使用您的库的其他开发人员仍然可以编写他们自己的实现类, 这些实现类可能使用不同的技术或算法来实现相同的结果｡
‫这也是为什么我们在使用的库中遇到这么多接口, 却很少觉得有必要编写自己的接口,
‫因为我们自己不编写库｡
‫最后要注意的是, 重要的是要理解接口是如何在这一点上实现的｡
‫当然, 当我们使用不同的技术, 如WPF和ASP｡ NET和C
‫sharp大师课, 我们将开始更多地使用接口, 这将有助于您在未来更好地理解它们｡
‫好吧, 我会的
‫所以非常感谢观看这段视频｡
‫下一场见｡