你能帮我理解一个实际例子中的抽象类和接口的用法吗?

你能否给我一个对抽象类和inheritance使用几乎过于简单化的理解并帮助我,这样我才能真正理解这个概念以及如何实现? 我有一个项目,我正在努力完成,并且失去了如何实施。 我一直在和我的教授聊天,并被告知,如果我无法弄明白,我可能还没准备好上课。 我已经完成了prequestite课程,但仍然无法理解这些概念。

为了澄清,到目前为止我所做的项目如下。 我还没有填写狗/猫类等。 你能指点一下吗? 我不是要求任何人给我“答案”。 我只是迷失在哪里。 我参加在线课程,他与我的沟通工作一直令人不安。 我刚刚完成了所有其他课程的4.0,所以我愿意付出努力,但我对这些概念的理解以及如何实际应用它们感到迷茫。

是否有任何意见或帮助可以让我在这个项目中取得进一步进展?

我要实现的内容如下:

概述:

本练习的目的是演示Interfaces,Inheritance,Abstract classes和Polymorphism的使用。 您的任务是获取提供的程序shell并添加适当的类和相应的类成员/方法,以使此程序正常运行。 您不能对提供的任何代码进行更改,您只能添加您编写的类。 尽管有许多方法可以使程序正常工作,但您必须使用演示接口使用的技术,
inheritance,抽象类和多态。 同样,为了清楚起见,您可以添加到提供的代码,但不能更改或删除任何代码。 提供的代码将使用非常少的附加代码,并将满足练习的要求。

如果成功完成分配,程序运行时应输出以下语句:

我的名字是Spot,我是一只狗

我的名字是费利克斯,我是一只猫

要求:

1)您必须有一个名为“Animal”的抽象基类,Dog和Cat类可以从中派生出来。

2)Animal基类必须从接口’IAnimal’派生,它是唯一应该从IAnimal派生的类。

3)由于所有动物都有一个名字,一个名字不是一个特定于狗或猫的属性,动物

基类应该是存储名称的位置以及实现WhatIsMyName get-property的位置。

4)您需要创建一个仅从Animal基类派生的Dog和Cat类。

5)Dog和Cat类应该实现WhatAmI get-property并返回相应的字符串值。

您无法更改的代码:

using System; namespace IT274_U2 { public interface IAnimal { string WhatAmI { get; } string WhatIsMyName { get; } } public class TesterClass { public static void DescribeAnimal(IAnimal animal) { Console.WriteLine("My name is {0}, I am a {1}", animal.WhatIsMyName, animal.WhatAmI); } static void Main(string[] args) { Dog mydog = new Dog("Spot"); Cat mycat = new Cat("Felix"); DescribeAnimal(mydog); DescribeAnimal(mycat); } } } 

///////////////////////

我编写的代码到目前为止:

 using System; namespace IT274_U2 { public interface IAnimal { string WhatAmI { get; } string WhatIsMyName { get; } } public class Dog { public abstract string WhatAmI { get; set; } }//end public class Dog public class Cat { public abstract string WhatIsMyName { get; set; } }//end public class Cat public abstract class Animal : IAnimal { // fields protected string Dog; protected string Cat; // implement WhatIsMyName //properties public abstract String Dog { get; set; } public abstract String Cat { get; set; } public abstract string WhatIsMyName(); } //end public abstract class Animal public class TesterClass { public static void DescribeAnimal(IAnimal animal) { Console.WriteLine("My name is {0}, I am a {1}", animal.WhatIsMyName, animal.WhatAmI); } static void Main(string[] args) { Dog mydog = new Dog("Spot"); Cat mycat = new Cat("Felix"); DescribeAnimal(mydog); DescribeAnimal(mycat); } } } 

编辑:

我已经为每个课程取出了代码体 – 如果你想看到我的答案,看看编辑修订:)

首先我们定义接口

 public interface IAnimal { string WhatAmI { get; } string WhatIsMyName { get; } } 

任何实现此接口的类都必须实现这些属性。 界面就像合同; 实现接口的类同意提供接口的方法,属性事件或索引器的实现。

接下来,我们需要定义您的抽象Animal类

 public abstract class Animal : IAnimal { //Removed for Training, See Edit for the code } 

类是抽象的事实表明该类仅用于其他类的基类。 我们已经实现了界面的两个属性,并且还有一个私有字段来存储动物名称。 此外,我们已经使WhatAmI属性访问器抽象化,以便我们可以在每个派生类中实现我们自己的特定属性访问器逻辑,并且还定义了一个接受字符串参数的构造函数,并将该值赋给_name private字段。

现在,我们来定义我们的CatDog

 public class Dog : Animal { //Removed for Training, See Edit for the code } public class Cat : Animal { //Removed for Training, See Edit for the code } 

这两个类都inheritance自Animal ,每个类都有一个构造函数,用于定义字符串参数,并将该参数作为参数传递给基础构造函数。 此外,每个类都为WhatAmI实现了它自己的属性访问WhatAmI ,分别返回了它们类型的字符串。

对于其余的代码

 public class Program { public static void DescribeAnimal(IAnimal animal) { Console.WriteLine("My name is {0}, I am a {1}", animal.WhatIsMyName, animal.WhatAmI); } static void Main(string[] args) { Dog mydog = new Dog("Spot"); Cat mycat = new Cat("Felix"); DescribeAnimal(mydog); DescribeAnimal(mycat); Console.ReadKey(); } } 

静态方法DescribeAnimal接受一个IAnimal作为参数,并写出由传入的IAnimalWhatIsMyNameWhatAmI属性访问器返回的值。

由于Animal实现了IAnimalDogCat都inheritance自Animal ,因此任何CatDog对象都可以作为参数传递给DescribeAnimal方法。

我希望我已经清楚地解释了这一点,如果有人觉得我的选择需要收紧,请发表评论,我很乐意编辑我的答案。

接口和抽象类之间的主要区别在于,在接口中,您只定义应该是实现此接口的对象的公共方法和属性。 抽象类提供了一些基本实现,但有一些“空白” – inheritance者需要实现的抽象方法。

我不会为你做功课,而是一个提示:动物类不应该包含任何特定于狗和猫的东西。

你很亲密,但要比这更难实现。

我不想给你答案;)但这里有一些指示。

首先,您要创建3个类和1个接口。 但是,我相信你可能遗漏的一件事是你需要3种不同类型的对象(从“最少定义”到“最定义”):

1)接口
这是IAnimal – 可以通过任何可以像动物一样行动的东西来实现

2)抽象基类这是动物calss – 动物的任何东西应该来自Animal,但这些不能直接创造。 如果你假装自己是上帝,你就不会制造动物,你会制造一只狗,猫,松鼠或者模糊的兔子

3)Animal的具体实现这些是实际的类本身。 这就是你创造的。 在你的情况下狗或猫。

这里的诀窍是你只能创建具体的类,但你可以使用IAnimal或Animal(接口或抽象基类)来操纵和使用任何动物(或者,在接口的情况下,任何像动物一样的东西)

一般来说:

  • 接口描述对象将响应的方法。 它是对象承诺满足的契约。

  • 抽象类描述了基本function,并为子类提供了专门的function。

因此,基本上,当您希望对象本质上不同时,使用接口,响应相同的特定方法。

当你需要某个类的专用版本时,你可以使用抽象类。

假设您要创建一个系统,其中任何类型的对象都可以通过唯一的ID标识,并且您不关心它们所属的类。

你可能有:

  • 动物

  • 运输

  • 电脑小工具。

  • 随你。

由于它们是不相关的主题,您可以选择实现和界面,让我们说:

 public interface IIdentifiable { public long GetUniqueId(); } 

所有想要满足此契约的类都将实现该接口。

 public class IPod: IIdentifiable { public long GetUniqueId() { return this.serialNum + this.otherId; } } public class Cat: IIdentifiable { public long GetUniqueId() { return this..... } } 

两者,以及IPod和Cat都具有非常不同的性质,但它们都可以响应将在目录系统中使用的“GetUniqueId()”方法。

然后它可以像这样使用:

  ... IIdentifiable ipod = new IPod(); IIdentifiable gardfield = new Cat(); store( ipod ); store( gardfield ); .... public void store( IIdentifiable object ) { long uniqueId = object.GetUniqueId(); // save it to db or whatever. } 

另一方面,您可能有一个抽象类定义对象可能具有的所有常见行为,并让子类定义专用版本。

  public abstract class Car { // Common attributes between different cars private Tires[] tires; // 4 tires for most of them private Wheel wheel; // 1 wheel for most of them. // this may be different depending on the car implementation. public abstract void move(); } class ElectricCar: Car { public void move() { startElectricEngine(); connectBattery(); deploySolarShields(); trasnformEnertyToMovemetInWheels(); } } class SteamCar: Car { public void move() { fillWithWather(); boilWater(); waitForCorrectTemperature(); keepWaiting(); releasePreasure.... } } 

这里,两种汽车,以不同的方式实现“移动”方法,它们仍然在基类中共享共同的东西。

为了使事情更有趣,这两辆车也可以实现de IIdentifiable接口,但通过这样做,他们只是承诺响应GetUniqueId方法,而不是作为汽车的性质。 这就是为什么自己的汽车可能无法实现该界面。

当然,如果标识可以基于汽车可能具有的公共属性,则GetIdentifiableId可以由基类实现,并且子类将inheritance该方法。

// case 1 …每个子类实现接口

  public class ElectricCar: Car, IIdentifiable { public void move() { ..... } public long GetUniqueId() { .... } } public class SteamCar: Car, IIdentifiable { public void move() { ..... } public long GetUniqueId() { .... } } 

情况2,基类实现接口,子类从中受益。

  public abstract class Car: IIdentifiable { // common attributes here ... ... ... public abstract void move(); public long GetUniqueId() { // compute the tires, wheel, and any other attribute // and generate an unique id here. } } public class ElectricCar: Car { public void move() { ..... } } public class SteamCar: Car { public void move() { ..... } } 

我希望这有帮助。

  1. 接口是合同。 您可以在此处描述您将提供的function,而无需任何实现细节

  2. 抽象类是一个类,其目的是在其子类之间共享实现细节。 由于它仅用于代码共享/分解目的,因此无法实例化

  3. 您的实际类将inheritance自您的抽象类,并在使用抽象类中共享的代码时实现其特定于类的function(如果需要)。

说实话,无论是否是家庭作业问题,它都让我感到不知道这个行业中不知道这一点的人数。 所以我会回答。

接口抽象实现,抽象类也是如此。 没有“vs”因为你可以创建一个实现接口的抽象类。 所以不要以为他们彼此交战。

因此,当您不希望消费者对实现了解太多时,可以使用EITHER。 接口在这项工作上要好一点,因为它没有实现,它只是说明了消费者可以按下它们返回的值的哪些按钮,并发送抽象类可能比这更多地说明(或甚至更多!) 。 所以如果你只是把这一点放在板上你只需要接口。 Ergo,第二点:

当您想要在接口的两个不同实现之间共享公共代码时,使用抽象类。 在这种情况下,两个具体实现都inheritance自实现接口的抽象类。

简单的例子是IDataStore。 SavingToATextFile数据存储区只是一个实现IDataStore的类。 但是,MsSqlDataStore和MySqlDataStore将共享公共代码。 它们都将inheritance自实现IDataStore的抽象类SqlDataStore。

抽象类:为派生类建立一个基础,它们为所有派生类提供契约。 它强制执行heirarchies

接口:

接口不是类,它是方法的定义。

一个类可以包含多个接口,但只能包含一个抽象类。

我希望有所帮助

基本上,接口定义了所有实现者必须提供的“合同”(即一组操作/属性)。 在这种情况下,IAnimal接口需要WhatAmI和WhatIsMyName属性。 抽象类可以提供某些function,但也会留下一些必须由其子类实现的操作。

在您的示例中,Animal基类能够提供WhatIsMyNamefunction,因为“Name”是所有动物的属性。 但是,它不能提供’WhatAmI’属性,因为只有特定的子类知道它们是什么’类型’。

您发布的示例代码的问题在于,Animal类知道它的子类,它不应该具有它

另一个建议 – (稍微偏离主题,但仍然相关)

出于学习目的,我建议避免使用自动属性。 如果您明确地实现它们,它将帮助您了解正在发生的事情。

例如,而不是做:

 class SomeClass { public string MyProperty { get; set; } } 

尝试自己实现:

 class SomeClass { public string MyProperty { get { return "MyValue"; // Probably a private field } set { // myField = value; or something like that } } 

我之所以提到这一点,是因为在这种特殊情况下它会帮到你 由于您使用的是自动属性,编译器会为您“填空”,在您的情况下,我认为这会阻止您获得一些非常有用的编译器错误。 当试图理解这些概念是如何工作的时候,自己做这项工作通常会让事情变得更容易,而不是更难。