Можете ли вы помочь мне понять на практике пример использования абстрактных классов и интерфейсов? - PullRequest
5 голосов
/ 09 марта 2009

Можете ли вы дать мне слишком упрощенное представление об использовании абстрактного класса и наследования и помочь мне, чтобы я мог по-настоящему понять концепцию и способы ее реализации? У меня есть проект, который я пытаюсь завершить, и теряюсь, как его реализовать. Я болтал с моим профессором, и мне в значительной степени сказали, что, если я не могу понять это, я, вероятно, не готов к курсу. Я ПРЕОБРАЗОВАЛ курсы предварительного обучения и до сих пор не могу понять эти концепции.

Для пояснения, проект, который я сделал до сих пор, находится ниже. У меня еще нет классов по собакам и кошкам и т.д. Можете ли вы дать мне указатель. Я не прошу никого дать мне «ответы». Я просто заблудился, куда идти с этим. Я беру онлайн-курсы, и его усилия по общению со мной вызывают беспокойство. Я только что закончил с 4.0 со всеми другими моими курсами, поэтому я готов приложить усилия, но я потерял понимание этих концепций и того, как ПРАКТИЧЕСКИ применять их.

Любые комментарии или помощь, которые позволят мне продвинуться дальше в этом проекте?

Описание того, что я должен реализовать, выглядит следующим образом:

Обзор:

Цель этого упражнения состоит в том, чтобы продемонстрировать использование интерфейсов, Наследование, Абстрактные классы и Полиморфизм. Ваша задача взять прилагаемая программная оболочка и ДОБАВИТЬ соответствующие классы и соответствующие члены класса / методы, чтобы получить это программа для правильной работы Ты можешь не вносить изменения в любой код при условии, вы можете добавить только классы ты пишешь. Хотя есть множество способов получить программу работая, вы должны использовать методы, которые продемонстрировать использование интерфейсов,
Наследование, Абстрактные классы и Полиморфизм. Опять же, чтобы прояснить, Вы можете добавить к предоставленному коду, но Вы не можете изменить или удалить любой из Это. Код, который предоставляется работать с очень небольшим дополнительным кодом и будет удовлетворять требованиям упражнение.

Если вы успешно завершили назначение, ваша программа должна выводить следующие операторы при запуске:

Меня зовут Спот, я - собака

Меня зовут Феликс, я кошка

Требования:

1) У вас должна быть абстрактная база класс под названием «Животное», из которого Собака и Кошка уроки.

2) Базовый класс Animal должен быть производным из интерфейса «IAnimal», это единственный класс, который должен быть производным от IAnimal.

3) Поскольку все животные имеют имя и имя не является атрибутом, который специфичные для собаки или кошки, животное

базовый класс должен быть там, где имя хранится и где WhatIsMyName get-property реализовано.

4) Вам нужно создать собаку и Класс Cat, который будет производным только от Животный базовый класс.

5) Классы собак и кошек должны реализовать WhatAmI get-свойство и вернуть соответствующее строковое значение.

Код, который вы не можете изменить:

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 ]

6 голосов
/ 09 марта 2009

Основное различие между интерфейсом и абстрактным классом состоит в том, что в интерфейсе вы только определяете, какими должны быть открытые методы и свойства объекта, реализующего этот интерфейс. Абстрактный класс обеспечивает некоторую базовую реализацию, но имеет некоторые «пробелы» - абстрактные методы, которые должен реализовать наследник.

Я не собираюсь делать за вас домашнее задание, но подсказка: класс Animal НЕ должен содержать ничего особенного для собак и кошек.

6 голосов
/ 09 марта 2009

EDIT:

Я взял тело кода для каждого класса - Если вы хотите увидеть мой ответ, взгляните на правки редактирования:)

Сначала мы определим интерфейс

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 таким образом, чтобы мы могли реализовать собственную логику доступа к конкретному свойству в каждом производном классе, а также определили конструктор, который принимает строковый аргумент и присваивает значение закрытому полю _name. .

Теперь давайте определим наши Cat и 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 принимает IAnimal в качестве аргумента и записывает значения, возвращаемые средствами доступа к свойствам WhatIsMyName и WhatAmI для переданных в IAnimal.

Поскольку Animal реализует IAnimal и оба Dog и Cat наследуются от Animal, любой объект Cat или Dog может быть передан в качестве параметра методу DescribeAnimal.

Я надеюсь, что я объяснил это ясно. Если кто-то считает, что мой выбор слов нуждается в ужесточении, пожалуйста, прокомментируйте, и я буду рад отредактировать мой ответ.

3 голосов
/ 09 марта 2009

Вы близки, но делаете это жестче, чем нужно.

Я не хочу давать вам ответ;) но вот несколько советов.

Сначала вы создаете 3 класса и 1 интерфейс. Тем не менее, я считаю, что вам может не хватать одной вещи: вам нужно 3 разных типа объектов (от «наименее определенных» до «наиболее определенных»):

1) Интерфейс
Это IAnimal - и может быть реализовано любым, что может действовать как животное

2) Абстрактный базовый класс Это животное Животное - все, что ЕСТЬ животное, должно происходить от Животного, но оно не может быть создано напрямую. Если вы притворяетесь, что вы Бог, вы не делаете Животное, вы делаете Собаку, Кошку, Белку или Пушистика

3) Конкретная реализация животного Это сами классы. Это то, что вы создаете. Собака или кошка в вашем случае.

Хитрость в том, что вы можете создавать только конкретные классы, но вы можете использовать IAnimal или Animal (интерфейсы или абстрактные базовые классы) для манипулирования и работы с любым животным (или, в случае интерфейсов, с любым, что действует как животное)

2 голосов
/ 09 марта 2009

Вообще говоря:

  • Интерфейсы описывают методы, на которые будет реагировать объект. Это контракт, который объект обязуется выполнить.

  • Абстрактные классы описывают основные функциональные возможности и предоставляют специализированные функциональные возможности подклассу.

Таким образом, в основном вы используете интерфейс, когда хотите, чтобы объекты, отличающиеся по своей природе, реагировали на один и тот же конкретный метод.

И вы используете абстрактный класс, когда вам нужны специализированные версии какого-либо класса.

Допустим, вы хотите создать систему, в которой любой тип объекта может быть идентифицирован по уникальному идентификатору, и вам все равно, к какому классу они принадлежат.

Возможно, у вас есть:

  • Животные

  • Транспорт

  • Компьютерные гаджеты.

  • Whatever.

Поскольку это не связанные темы, вы можете выбрать реализацию и интерфейс, скажем:

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, а не по характеру машины. Вот почему Car сам не может реализовать этот интерфейс.

Конечно, если идентификация может быть основана на общих атрибутах, которые могут иметь автомобили, 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()
       {
         .....
       }
  }

Надеюсь, это поможет.

1 голос
/ 09 марта 2009

Честно говоря, меня пугает количество людей в отрасли, которые этого не знают, независимо от того, является ли это домашним заданием или нет. Поэтому я отвечу.

Интерфейсы абстрактной реализации и абстрактные классы. Здесь нет «vs», потому что вы можете создать абстрактный класс, который также реализует интерфейс. Так что не думайте, что они воюют друг с другом.

Следовательно, EITHER можно использовать, если вы не хотите, чтобы потребитель слишком много знал о реализации. Интерфейс немного лучше в этой работе, потому что он не имеет реализации, он просто указывает, какие кнопки потребитель может нажимать на значения, которые он возвращает и отправлять, где абстрактный класс может указывать немного больше, чем это (или даже намного больше!) , Так что, если вы просто возьмете эту точку на себя, вам понадобятся только интерфейсы. Ergo, точка вторая:

В качестве абстрактного класса используется, когда вы хотите поделиться общим кодом между двумя различными реализациями интерфейса. В этом сценарии две конкретные реализации обе наследуются от абстрактного класса, который реализует интерфейс.

Простой пример - IDataStore. Хранилище данных SavingToATextFile - это просто класс, который реализует IDataStore. Однако MsSqlDataStore и MySqlDataStore будут использовать общий код. Они оба будут наследовать от абстрактного класса SqlDataStore, который реализует IDataStore.

1 голос
/ 09 марта 2009
  1. Интерфейс - это контракт. Это место, где вы хотите описать предоставляемые вами функции без каких-либо подробностей реализации

  2. Абстрактный класс - это класс, цель которого - делиться деталями реализации между своими подклассами. Так как он здесь только для целей совместного использования кода / факторизации, он не может быть создан

  3. ваш фактический класс унаследует от вашего абстрактного класса и реализует его специфичные для класса функциональные возможности, используя при необходимости код, общий для абстрактного класса.

0 голосов
/ 09 марта 2009

Другое предложение - (немного не по теме, но все еще связано)

Рекомендую в учебных целях избегать автоматических свойств. Это поможет вам понять, что происходит, если вы реализуете их явно.

Например, вместо того, чтобы делать:

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

Я упоминаю об этом, потому что это поможет вам в этом конкретном случае. Поскольку вы используете автоматические свойства, компилятор «заполняет пробелы» для вас, и в вашем случае, я думаю, что он предотвращает получение очень полезных ошибок компилятора. Пытаясь понять, как работают эти концепции, выполнение работы самостоятельно обычно облегчает, а не усложняет.

0 голосов
/ 09 марта 2009

По сути, интерфейс определяет «контракт» (т. Е. Набор операций / свойств), который должны предоставлять все разработчики. В этом случае для интерфейса IAnimal требуются свойства WhatAmI и WhatIsMyName. Абстрактные классы могут предоставлять определенную функциональность, но также оставляют некоторые операции, которые должны быть реализованы их подклассами.

В случае вашего примера базовый класс Animal может предоставить функциональность WhatIsMyName, поскольку «Имя» является свойством всех животных. Однако он не может предоставить свойство WhatAmI, поскольку только определенные подклассы знают, к какому типу они относятся.

Проблема с примером кода, который вы разместили, заключается в том, что класс Animal знает о своих подклассах, которых у него не должно быть

0 голосов
/ 09 марта 2009

Абстрактные классы: Установить базу для производных классов, они предоставляют контракт для всех производных классов. Это навязывает иерархии

Интерфейсы:

Интерфейс - это не класс, это определение методов.

Класс может наследовать несколько интерфейсов, но только один абстрактный класс.

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...