Это пример полиморфизма? - PullRequest
       15

Это пример полиморфизма?

9 голосов
/ 04 апреля 2011

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

class Human
{
   public virtual void CleanTheRoom()
   {
   }
}
class Woman:Human
{
   public override void CleanTheRoom()
   {
     //women clean faster
   }
}
class Man:Human
{
   public override void CleanTheRoom()
   {
     //men clean slower, different code here
   }
}
class Child:Human
{
   public override void CleanTheRoom()
   {
     //empty ... children are lazy :)
   }
}

Должен ли я объяснить, что это полиморфизм, потому что все производные классы из базового класса Human содержат метод CleanTheRoom, но каждый из них реализует по-своему?

Ответы [ 8 ]

21 голосов
/ 04 апреля 2011

Преимущество полиморфизма наступает, когда вы хотите вызвать метод CleanTheRoom() для некоторого типа Human, но вам не важно, какой именно.

Имея CleanTheRoom(), определенную вУровень базового класса, Human, вы можете писать более короткий и понятный код в любом месте вашего приложения, когда вы работаете с экземпляром Human, будь то Man, Woman или Child.

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

Хорошо:

private void SomeMethod(Human h)
{
    //some logic
    h.CleanTheRoom();
    //more logic
}

Плохо:

private void SomeMethod(Human h)
{
    //some logic
    if (h is Man)
        CleanRoomSlowly();
    else if (h is Woman)
        CleanRoomQuickly();
    else if (h is Child)
        GoofOff();
    //some logic
}
16 голосов
/ 04 апреля 2011

То, что у вас есть, является хорошим примером наследования. Полиморфизм относится конкретно к возможности ссылаться на объекты разных типов с использованием одного типа (родительский класс или интерфейс), что делает возможным этот тип наследования. Вот так:

List<Human> humans = new ArrayList<Human>();

humans.add(new Woman());
humans.add(new Woman());
humans.add(new Man());
humans.add(new Child());
humans.add(new Child());

foreach(Human hum in humans) {
   hum.CleanTheRoom(); //I don't know the type of hum, but I don't care
}

Скажем, я собирал экземпляры Человека из разных мест - я не знаю, к какому типу относится каждый. Но я все еще могу перебрать их и вызвать CleanTheRoom (), потому что они совместно используют родительский класс.

Я добавлю пример из реальной жизни. Скажем, у меня есть класс Invoice с различными подклассами для различных типов счетов-фактур - возможно, существуют различные виды Invoice для клиентов обслуживания по сравнению с клиентами, которые совершают разовые покупки. Иногда я глубоко забочусь о различиях, и я имею дело только с одним типом. Но иногда я хочу просмотреть все счета за этот месяц и распечатать их. Если у родительского класса есть метод print() (который может быть реализован по-разному разными типами), я могу это сделать.

0 голосов
/ 14 июля 2018

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

0 голосов
/ 04 марта 2013
class Program
{
    static void Main(string[] args)
    {
        List<ICleanTheRoom> cleanerList = new List<ICleanTheRoom>
            {
                new Child(), 
                new Woman(), 
                new Man()
            };
        foreach (var cleaner in cleanerList)
        {
            cleaner.CleanTheRoom();
        }
    }
}

internal interface ICleanTheRoom
{
    void CleanTheRoom();
}

// No need for super type

//class Human : ICleanTheRoom
//{
//   public virtual void CleanTheRoom()
//   {
//   }
//}


internal class Woman : ICleanTheRoom
{
    public void CleanTheRoom()
    {
        throw new NotImplementedException();
    }
}

class Man: ICleanTheRoom
{
    public void CleanTheRoom()
    {
        throw new NotImplementedException();
    }
}

class Child: ICleanTheRoom
{
    public void CleanTheRoom()
    {
        throw new NotImplementedException();
    }
}
0 голосов
/ 25 июля 2012

Пример в C #:

Это мой файл класса

class parent
    {
        public virtual string saySomething(string s)
        {
            return s+":Parent";
        }
    }
    class man : parent
    {
        public override string saySomething(string s)
        {
            return s+":Man";
        }
    }
    class woman : parent
    {
        public override string saySomething(string s)
        {
            return s+":Woman";
        }
    }
    class child : parent
    {
        public override string saySomething(string s)
        {
            return s+":Child";
        }
    }

Создание четырех кнопок и метки.

Вот реализация в простой форме1

private void Form1_Load(object sender, EventArgs e)
        {
             p1= new parent();       

        }

        private void button1_Click(object sender, EventArgs e)
        {            
            label1.Text = p1.saySomething("I am parent!");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            p1 = new man();
            label1.Text = p1.saySomething("I am man!");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            p1 = new woman();
            label1.Text = p1.saySomething("I am woman!");
        }

        private void button4_Click(object sender, EventArgs e)
        {
            p1 = new child();
            label1.Text = p1.saySomething("I am child!");
        }

Это полиморфизм во время выполнения? P1 это объект. В зависимости от ситуации (контекста), нажатие кнопки выполняет разные части кода. Таким образом, p1 ведет себя по-разному в зависимости от события click.

0 голосов
/ 05 апреля 2011

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

В функциональном программировании функции являются первоклассными концепциями в отличие от ООП, где объекты являются высшими.

Полиморфизм для ООП - это то же самое, что сопоставление с образцом для ФП. Вот функция, которая использует сопоставление с образцом (используя синтаксис стиля ML).

 let f x =
        match x with
        | T -> //do stuff with a T to return some value
        | S -> //do stuff with an S to return some value
        | U -> //do stuff with a U to return some value
        | V -> //do stuff with a V to return some value

Таким образом, когда вы используете функцию f, вы можете передавать ей объект типа T, S, U или V. В строго типизированных языках FP, таких как F #, тип x обозначается T|S|U|V. Такие типы обычно называются типами сумм или теговыми союзами.

Если мы исправим ваш пример, чтобы сделать Human абстрактным классом, тогда станет ясно, что полиморфизм в ООП просто дает вам способ выражения типа суммы.

Таким образом, CleanTheRoom - это функция, которая принимает тип Human. Но Human - это просто имя для типа Man|Woman|Child, который является типом суммы. Большая разница между языками, такими как C #, и функциональными языками, такими как F #, заключается в том, что один рассматривает объекты как вещи верхнего уровня, а другой - как функции верхнего уровня. Кроме того, все в языках ООП, таких как C #, должны иметь имена. На функциональном языке мы можем обозначить тип Man|Woman|Child без необходимости явно называть его.

Ключ не в том, чтобы думать о коде как о различных методах CleanTheRoom, а о том, чтобы CleanTheRoom воспринимать как один метод, принимающий тип Man|Woman|Child (который называется Human). Полиморфизм - это просто деталь реализации.

Таким образом, полиморфизм (особенно с абстрактными классами) в основном просто дает вам возможность называть типы сумм и выполнять сопоставление с образцом.

См:

0 голосов
/ 05 апреля 2011

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

Допустим, у вас есть простая форма CRUD. Это код кнопки сохранения:

var Client = PopulateDTO(); //put all the values in the controls, to an object

if(Action==Actions.Create){
  _repository.Create(Client);
}
else if(Action==Actions.Update){
  _repository.Update(Client);
}
else if(Action==Actions.Delete){
  _repository.Delete(Client);
}

this.Close();

Этот код работает, но это плохой код, и его трудно прочитать. Давайте использовать полиморфизм (и шаблон стратегии):

public abstract class BaseStrategy{
  abstract void Do(ClientDto Client);
}

public class CreateStrategy:BaseStrategy{
  public override void Do(ClientDto Client){
    _repo.Save(Client);
  }
}

public class UpdateStrategy:BaseStrategy{
  public override void Do(ClientDto Client){
    _repo.Update(Client);
  }
}

public class DeleteStrategy:BaseStrategy{
  public override void Do(ClientDto Client){
    _repo.Delete(Client);
  }
}

Итак, у нас есть абстрактный класс и 3 реализации, каждая из которых делает что-то с клиентским объектом. Теперь код кнопки сохранения в форме будет:

BaseStrategy stg = GetCorrectStrategy();

var Client = PopulateDTO();

stg.Do(Client);

this.close;

И метод GetCorrectStrategy () создаст правильную реализацию Стратегии в зависимости от того, создает ли пользователь, редактирует или удаляет клиент.

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

0 голосов
/ 04 апреля 2011

Да, это правильно.И вы можете вызывать метод CleanTheRoom (), не зная, какой это "человек".

Здесь у вас есть несколько основных примеров.

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