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

时间:2009-03-09 17:23:26

标签: c# interface abstract-class

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

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

任何可以让我在这个项目中取得进一步进展的评论或帮助?

我要实施的内容如下:

  

概述:

     

本练习的目的是为了   演示接口的使用,   继承,抽象类和   多态性。你的任务是采取   提供的程序shell和ADD   适当的类和相应的   获得这个的类成员/方法   程序正常运行。你可以   不要对任何代码进行更改   提供,您只能添加类   你写。虽然有   获得该计划的方法很多   工作,你必须使用的技术   演示接口的使用,
  继承,抽象类和   多态性。再次,说清楚,   你可以添加到提供的代码但是   你不能改变或删除任何   它。提供的代码将   使用非常少的额外代码   并将满足要求   练习。

     

如果你顺利完成了   分配,你的程序应该输出   运行时的以下语句:

     

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

     

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

     

要求:

     

1)你必须有一个抽象的基础   类叫'动物'的类   狗和猫类派生。

     

2)Animal基类必须派生   来自界面'IAnimal',它是   唯一应该来自的课程   IAnimal。

     

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

     

基类应该是名称所在的位置   存储和WhatIsMyName的位置   get-property已实施。

     

4)你需要创建一个狗和一个   Cat类只能从中派生出来   动物基类。

     

5)狗和猫类应该   实现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);
        }
    }
}

9 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:6)

修改

我已经为每个课程提取了代码 - 如果你想看到我的答案,请看一下编辑修订:)

首先我们定义interface

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

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

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

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

类为abstract的事实表明该类仅用作其他类的基类。我们已经实现了接口的两个属性,并且还有一个私有字段来存储动物名称。另外,我们已经创建了WhatAmI属性访问器摘要,以便我们可以在每个派生类中实现我们自己的特定属性访问器逻辑,并且还定义了一个接受字符串参数的构造函数,并将值赋给{{1私有领域。

现在,让我们定义我们的_nameCat

Dog

这两个类都继承自public class Dog : Animal { //Removed for Training, See Edit for the code } public class Cat : Animal { //Removed for Training, See Edit for the code } ,每个类都有一个构造函数,用于定义字符串参数,并将该参数作为参数传递给基础构造函数。此外,每个类都为Animal实现了它自己的属性访问器,分别返回了它们类型的字符串。

代码的其余部分

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作为参数,并写出IAnimalWhatIsMyName属性访问器为传入的WhatAmI返回的值}。

由于IAnimal实施Animal,而IAnimalDog都继承自Cat,因此任何AnimalCat对象都可以作为参数传递给Dog方法。

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

答案 2 :(得分:3)

你很亲密,但要比实际需要的更难。

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

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

1)界面
  这是IAnimal - 可以通过任何可以像动物一样的方式实现

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

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

这里的技巧是你只能创建具体的类,但你可以使用IAnimal或Animal(接口或抽象基类)来操纵和使用任何动物(或者,在接口的情况下,任何行为类似于动物)

答案 3 :(得分:2)

一般来说:

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

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

所以,基本上当你想要那些性质不同的对象时,你会使用一个接口,回应相同的特定方法。

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

假设您想要创建一个系统,其中任何类型的对象都可以通过唯一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可以由基类实现,并且子类将继承该方法。

// 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()
       {
         .....
       }
  }

我希望这会有所帮助。

答案 4 :(得分:1)

  1. 界面是合约。您可以在此处描述您将提供的功能,而无需任何实施细节

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

  3. 您的实际类将继承自您的抽象类,并在使用抽象类中共享的代码时实现其特定于类的功能。

答案 5 :(得分:1)

说实话,不管是否是家庭作业问题,这让业内人士不知道这个问题。因此我会回答。

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

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

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

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

答案 6 :(得分:0)

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

接口:

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

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

我希望有帮助

答案 7 :(得分:0)

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

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

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

答案 8 :(得分:0)

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

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

例如,而不是:

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
        }
}

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