你们当中有多少人在阅读有关编程教程的知识时遇到了这样的示例:
/*
** Inheritance is useful when different classes share functionality. */
using System;
class Animal
{
protected string speakSound = "";
public void Speak() {
Console.WriteLine(speakSound);
}
}
class Cat : Animal
{
public Cat() {
this.speakSound = "Meow";
}
}
class Dog : Animal
{
public Dog() {
this.speakSound = "Woof";
}
}
class ZooClass
{
static void Main(string[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
cat.Speak(); // Prints Meow
dog.Speak(); // Prints Woof
}
}
阅读此示例后有多少人认为:
“是的,我知道如何在实际应用程序中使用它”
该示例的作用是解释继承的工作原理,但是没有提供任何线索来说明您可以使用它解决什么问题,以及为什么它比解决问题的替代方法更好。 这就像将锤子解释为“一种有用的工具,它具有木制部分和金属部分,然后用金属部分敲打东西使其爆炸”。
编程模式和技术是工具,这是用来使其更容易实现复杂的行为或逻辑,同时在保持代码的维护,更容易打造。 对于初学者来说,大多数现实生活中的例子可能太复杂了,但我认为在1000行现实生活中的例子与“ Cow gos moo”之间存在中间立场。
使用真实项目中的真实示例进行教学
从一个真正的问题开始。 如果可能,在实际项目中(忽略与当前问题无关的任何细节)
“适用于早期Westwood游戏的开源实时战略游戏引擎,例如Command&Conquer:用C#编写的Red Alert…”
在“命令与征服:红色警戒”中,您将担任指挥作战派系一部分的一般角色。 您的目标是收集资源,建立基地并训练一支军队来粉碎您的对手。
在这个游戏中,您可以建立一个名为Spy的单位,该单位可以渗透到敌方建筑物中,并且根据所渗透的建筑物,可以引起不同种类的效果。
一些示例包括(来自CNC Wiki ):
当选择建筑物时, 机场显示当前生产的单位
显示当前着陆飞机上的弹药量
发电厂显示五格垂直指示敌人的力量状态
矿石精炼厂显示产能指标和当前持有的矿石量
现在的问题是: 我应该如何实现渗透的不同效果?
// Not like this
if (building.name == "Airfield") { airfieldInfiltration(); }
if (building.name == "Power Plant") { powerPlantInfiltration(); }
if (building.name == "Ore Refinery" { oreRefineryInfiltration(); }
大多数建筑物无法渗透,因此创建基类似乎并不正确,但是所有建筑物的行为截然不同,因此将所有内容归为一个类也不是正确的。
读者理解问题之后,您将提出解决方案: 接口
OpenRA使用名为INotifyInfiltrated ( 在此声明 )的接口,该接口用于实现间谍进入敌方建筑物时的不同功能。 该接口针对任何可渗透的建筑物实现,并且效果行为可在每个不同的建筑物类内找到,而不是基类或if-else语句的大量对象。 (使用接口窃取现金的示例可以在此处找到。请注意,行为被包装在自己的类中,因为建筑物不是硬编码的,因此并不严格遵循所提供的示例,但是没有理由不能这样做) t)。
一个代码示例如下所示。 它不是自包含的,不会编译,但是我认为强制将其删除是有用的。 泡沫中不存在真正的问题。
public interface INotifyInfiltrated {
void Infiltrated(Player playerInfiltrating);
}
class Airfield : INotifyInfiltrated
{
public void Infiltrated(Player playerInfiltrating) {
// Displays currently produced unit when
// the building is selected
Unit producingUnit = this.GetCurrentlyProducingUnit()
producingUnit.revealToPlayer(playerInfiltrating);
// Displays amount of ammunition on
// currently landed aircraft
Unit landedUnit = this.GetCurrentlyLandedUnit();
landedUnit.revealStatsToPlayer(playerInfiltrating);
}
}
class PowerPlant : INotifyInfiltrated
{
public void Infiltrated(Player playerInfiltrating) {
// Displays a five-box vertical indicator
// of enemy power status
this.revealPowerStatusToPlayer(playerInfiltrating);
}
}
class OreRefinery : INotifyInfiltrated
{
public void Infiltrated(Player playerInfiltrating) {
// Displays capacity indicator
//and amount of presently held ore
this.revealOreStatusToPlayer(playerInfiltrating);
}
}
现在,读者已经看到了如何使用接口解决实际编程问题的实际示例。 只要遇到类似问题,所需行为“对某些人而言是相似的,而对所有情况而言并非如此”,则他们可以应用此方法。
因此,在下次阅读此内容(也许有人在问有关接口的信息)之后,您不必拖出不良的虚拟猫狗吠叫就可以表达您的意思了。
From: https://hackernoon.com/stop-abusing-virtual-animals-when-teaching-programming-a64adc93525a