English 中文(简体)
你能通过实际例子帮我理解抽象类和接口的使用吗?
原标题:
  • 时间:2009-03-09 17:23:26
  •  标签:

你能给我一个近乎过于简单的理解抽象类与继承使用的方式,并帮助我真正理解这个概念以及如何实现吗?我正在尝试完成一个项目,但不知道如何实现。我一直在与我的教授聊天,但被告诉说如果我无法理解,我可能还没有准备好这门课程。我已经学习了先修课程,并且仍然有困难理解这些概念。

为了澄清,我目前为止完成的项目如下。我还没有填写狗/猫类等信息。你能给我一点建议吗?我并不是要求别人给我“答案”。我只是不知道该怎么做。我正在上网课,他对我的沟通非常困扰。我在所有其他课程中都以4.0结尾,所以我愿意付出努力,但我对这些概念的理解和如何实际应用它们感到困惑。

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

我要实现的描述如下:

概述:

The purpose of this exercise is to demonstrate the use of Interfaces, Inheritance, Abstract classes, and Polymorphism. Your task is to take the supplied program shell and ADD the appropriate classes and corresponding class members/methods to get this program to function correctly. You may not make changes to any of the code supplied, you may only add the classes you write. Although there are numerous ways to get the program working, you must use techniques that demonstrate the use of Interfaces,
Inheritance, Abstract classes, and Polymorphism. Again, to make clear, you can add to the supplied code but you cannot change or delete any of it. The code that is supplied will work with very little additional code and will satisfy the requirements of the exercise.

If you successfully complete the assignment, your program should output the following statements when run:

我的名字是斑点,我是一只狗。

我的名字叫菲利克斯,我是一只猫。

要求:

1) You must have an abstract base class called Animal from which the Dog and Cat classes derive.

2) The Animal base class must derive from the Interface IAnimal , it is the only class that should derive from IAnimal.

3) Since all animals have a name and a name is not an attribute that is specific to a dog or a cat, the Animal

base class should be where the name is stored and where the WhatIsMyName get-property is implemented.

4) You will need to create a Dog and a Cat class that will derive only from the Animal base class.

5) The Dog and Cat classes should implement the WhatAmI get-property and return the appropriate string value.

您無法更改的代碼:

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

Sorry, there is no text provided to translate. Please provide a text to be translated.

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

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

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

接下来,我们需要定义您的抽象动物类。

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

班级是抽象的事实表明这个类仅被设计成其他类的基类。我们已经实现了接口的两个属性,并且还有一个私有字段用于存储动物名称。此外,我们已经将WhatAmI属性访问器设置为抽象的,以便我们可以在每个派生类中实现自己特定的属性访问逻辑,并定义了一个接受字符串参数并将其值分配给 _name 私有字段的构造函数。

现在,让我们定义我们的 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
}

两个类都继承自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接受一个IAnimal作为参数,并输出通过传入的IAnimal调用WhatIsMyNameWhatAmI属性访问器返回的值。

由于Animal实现了IAnimal,且DogCat均继承于Animal,因此任何CatDog对象都可以作为参数传递给DescribeAnimal方法。

我希望我已经清楚地解释了这一点。如果有人觉得我的措辞需要更紧凑,请评论,我会很乐意编辑我的回答。

问题回答

接口和抽象类的主要区别在于,接口只定义实现该接口的对象应具有的公共方法和属性。抽象类提供一些基本实现,但存在一些“缺口”——继承者需要实现的抽象方法。

我不会帮你做功课,但给你一个提示:Animal类不应该包含任何狗和猫特有的东西。

你很接近了,但是这比必须的更困难。

我不想给你答案 ;) 但这里有几个指导。

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

1) Interface
This is IAnimal - and can be implemented by anything that can act like an animal

2) Abstract Base Class This is the Animal calss - anything that IS an animal should derive from Animal, but these aren t creatable directly. If you pretend you re God, you don t make an Animal, you make a Dog, Cat, Squirrel, or FuzzyBunny

3) Concrete Implementation of Animal These are the actual classes themselves. This is what you create. Dog or Cat in your case.

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

一般来说:

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

  • 抽象类描述基本功能,并将特定功能委托给子类。

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

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

假设你想创建一个系统,其中任何类型的对象都可以通过唯一标识符进行识别,而你并不关心它们所属的类。

你可能有:

  • 动物 (dòng wù)

  • 交通 (jiāo tōng)

  • 电脑小玩意儿。

  • 随便。

由于它们是不相关的话题,您可以选择实现和界面,比如说:

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还是猫,它们的天性都非常不同,但它们都可能会响应“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....
        }
   }

在这里,两种不同的汽车用不同的方式实现“move”方法,但仍在基类中共享共同点。

为了让事情更有趣,这两辆汽车也可以实现IIdentifiable接口,但这样做只意味着它们承诺响应GetUniqueId方法,而不是因为它们是汽车的本质。这就是为什么汽车本身可能不实现该接口。

当然,如果车辆的身份识别可能基于其共同的属性,则GetIdentifiableId方法可以由基类实现,而子类将继承该方法。

案例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. 一个接口就是一个合约。这就是你想要描述你提供的功能但是没有任何实现细节的地方。

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

  3. 你的实际类将继承你的抽象类,并在需要时使用抽象类中分享的代码来实现其特定于类的功能。

说实话,这让我感到害怕,无论是否是课堂作业问题,都有这么多行业人士不知道这个。因此,我会回答。

接口和抽象类都具有抽象实现。没有“vs”,因为您也可以创建实现接口的抽象类。所以不要认为它们之间处于相互对立的状态。

因此,当你不想让消费者知道太多实现细节时,可以使用任何一个。接口在这方面的表现略好一些,因为它没有实现,只是指明了消费者可以按哪些按钮获取的值和发送的位置,而抽象类可能会比这多说明一些(甚至很多)。因此,如果你只考虑这一点,你只需要接口。因此,要点二:

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

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

Abstract Classes: Establish a base for derived classes they provide a contract for all derived classes. It enforces heirarchies

接口:

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

一个类可以继承多个接口,但只能继承一个抽象类。

我希望那能帮到你。

Basically, an interface defines a contract (i.e. a set of operations/properties) that all implementers must provide. In this case the IAnimal interface requires the WhatAmI and WhatIsMyName properties. Abstract classes may provide certain functionality, yet will also leave some operations which must be implemented by their subclasses.

In the case of your example, the Animal base class is able to provide the WhatIsMyName functionality since Name is a property of all animals. However, it cannot provide the WhatAmI property, since only specific subclasses know what type they are.

The problem with the sample code you posted, is that thet Animal class has knowledge of it s subclasses, which it should not have

Another suggestion - (slightly off topic, but still related)

I recommend, for learning purposes, to avoid automatic properties. It will help you understand what s happening if you implement them explicitly.

For example, instead of doing:

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

Try implementing this yourself:

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

I mention this because it will help you in this specific case. Since you re using automatic properties, the compiler is "filling in the blanks" for you, and in your case, I think it s preventing you from getting some very useful compiler errors. When trying to understand how these concepts work, doing the work yourself usually makes it easier, not harder.





相关问题
热门标签