Наследование или идентификатор - PullRequest
6 голосов
/ 16 марта 2010

Есть ли у кого-нибудь здесь мнения о том, когда наследовать пользователя и когда вместо него использовать идентификатор?

Пример наследования:

class Animal 
{
    public int Name { get; set; }
}

class Dog : Animal {}

class Cat : Animal {}

Пример идентификатора:

class Animal 
{
    public int Name { get; set; }

    public AnimalType { get; set; }
}

В каких ситуациях я предпочитаю какое решение и каковы плюсы и минусы для них?

/ Лина

Ответы [ 10 ]

6 голосов
/ 16 марта 2010

Это зависит от типа действий, которые необходимо выполнить в вашей системе. Например, если у вас есть какое-то общее действие, которое должно быть выполнено по-разному для каждого из ваших объектов, чем вы должны использовать наследование, например ::

class Shape 
{
    public abstract void Draw();
}

class Circle : Shape 
{
    public override void Draw()
    { 
        /* Custom implementation for Circle. */
    }
}

class Box : Shape 
{
    public override void Draw()
    { 
        /* Custom implementation for Box. */
    }
}

С другой стороны, если некоторый тип и объект больше похож на его свойство, вы должны использовать то, что вы называете «идентификатором»:

enum Color
{
    Red,
    Green,
    Blue
}

class Box
{
    public Color BoxColor { get; set; }
}

Здесь вы можете использовать наследование (но оно выглядит не очень хорошо): RedBox, BlueBox и т. Д. Разница в том, что все ящики (даже имеющие разный цвет) будут обрабатываться одинаково, и их поведение будет общий.

4 голосов
/ 16 марта 2010

То, что вы называете «идентификатором», я бы назвал подходом enum.

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

3 голосов
/ 16 марта 2010
  • Если единственное различие между животными - это их тип, используйте свойство AnimalType.

  • Если разные животные имеют разные реализации свойств и методов или дополнительные, создайте классы, производные от Animal.

    Если проверка на тип животного является распространенным случаем, рассмотрите возможность предоставления свойства AnimalType в качестве альтернативы лотам is / as.

2 голосов
/ 16 марта 2010

Наследование тесно связывает поведение кошки и собаки с поведением животного. Который может быть тем, что вы хотите.

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

Но вы можете пойти дальше.

Согласно шаблонам проектирования Gang of Fours вы должны

"Пропагандировать" композицию объекта "над" наследованием класса "."

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

Затем вы можете попытаться абстрагироваться от его поведения, а затем в этом поведении вы можете использовать наследование.

С этой структурой класса:

class Tail
{
  DoYourThing()
}

class WaggyTail : Tail
{
  DoYourThing()
  {
    // Wag
  }
}

class Noise
{
  DoYourThing()
}

class Bark : Noise
{
  DoYourThing()
  {
    // Bark
  }
}

class Talk : Noise
{
  DoYourThing()
  {
     // Talk
  }
}

class Animal
{
   public Noise { get; set; }
   public Tail { get; set; }
}

Вы можете настроить своих кошек и собак:

  Animal dog = new Animal { Noise = new Bark(), tail = new DoggyTail() }
  Animal cat = new Animal{ Noise = new Purr(), tail = new CattyTail() }

.. тогда когда вам нужна ваша супер порода, вы можете просто изменить их поведение

dog.Noise = new Talk ();

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

2 голосов
/ 16 марта 2010

Я бы использовал наследование, если у наследующих классов (в вашем примере Cat и Dog) другой интерфейс (методы или поля) или если они используются для выбора другого поведения. Например, в реальном проекте у меня есть базовый класс для генерации HTML-кода. В зависимости от ситуации я создаю правильный подкласс, который генерирует правильный HTML. У этих классов (в основном) один и тот же интерфейс, но их поведение настолько отличается, что я не хочу выбирать его с помощью if или switch.

1 голос
/ 16 марта 2010

При переходе от общего к специализированному я бы сказал: переходи по наследству. Таким образом (по отношению к вашему примеру) вам придется только один раз делать приемы, есть, спать и т. Д. Однако, если они находятся на одном уровне, было бы лучше просто использовать идентификатор. Например. Вы не хотели бы основывать кошку на собаке, потому что тогда вам придется отключить опции в дополнение к добавлению новых.

1 голос
/ 16 марта 2010

Наследование, на мой взгляд, предпочтительнее, когда поведение должно меняться в соответствии с заданным идентификатором. Например, если вы просто хотите предоставить свой метод Animal a walk(), вам не нужно указывать подклассы (поскольку собаки и кошки издалека ведут себя одинаково).

Однако, если вы хотите, чтобы у них был какой-то метод makeNoise(Mood mood), наследование будет полезно:

class Cat {
    public void makeNoise(Mood mood) {
        swithch(mood) {
            case happy:
                purr();
                break;
                // and so on
1 голос
/ 16 марта 2010

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

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

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

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

0 голосов
/ 16 марта 2010

Хорошо, мое новое эмпирическое правило будет состоять в том, чтобы перейти к наследованию, если классы ведут себя по-разному, в противном случае я пойду за какой-то идентификатор. (Конечно, окончательное решение будет зависеть от среды, в которой будут использоваться классы). Спасибо за все ваши ответы!

0 голосов
/ 16 марта 2010

Это очень просто, оба приходят, чтобы решить две разные проблемы, Когда у вас есть различные поведения , вы должны использовать Наследование, например, если у класса животных есть поведение «говорить», оно должно быть реализовано с использованием полиморфизма и наследования.

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