2015-08-11 5 views
1

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

public interface IMammal 
{ 
    void Eat(); 
} 

public interface IBarking 
{ 
    void Bark(); 
} 

Есть случаи IBarking и IMammal. Теоретически наше животное может быть любым из них или только одним. Cow - это, как вы можете видеть, IMammal, и Dog - IMammal и IBarking. В теории у нас может быть даже кто-то, кто может лаять, но не является млекопитающим.

public class Mammal : IMammal 
{ 
    public void Eat() 
    { 
     Console.Write("Om-nom-nom"); 
    } 
} 

public class Cow : Mammal 
{ 
} 

public class Dog : Mammal, IBarking 
{ 
    public void Bark() 
    { 
     Console.Write("Bark-bark!!!"); 
    } 
} 

Вот Farm, где только одно животное живет:

public class Farm 
{ 
    private readonly IMammal _animal; 

    public Farm(IMammal animal) 
    { 
     _animal = animal; 
    } 

    public void Feed() 
    { 
     _animal.Eat(); 
    } 

    public void Guard() 
    { 
     var dog = _animal as IBarking; 
     if (dog != null) 
      dog.Bark(); 
    } 
} 

Проблема, я вижу здесь, является то, что мы предполагаем, что IBarking всегда IMammal. Что не так с этим дизайном, как оно может быть исправлено?

+1

Вы предполагаете, что 'Собака' всегда' IMammal', какой она есть, хотя 'IMammal' не может быть' Dog'. Я не уверен, где вы видите, что «Ибаркинг» считается «IMammal» в коде? Вы выбираете конкретный тип, вы могли бы сделать что-то вроде «var barker = _animal as IBarking», что сделало бы ваш вопрос понятным ... Но даже это не предполагает, что «Ибаркинг» является млекопитающим, только то, что млекопитающее * может * реализовать его. –

+0

@RonBeyer Извините. Это моя ошибка. Я скорректировал код, чтобы теперь я перешел на «ИБаркинг». Ситуация в том, что я не могу предоставить какой-либо другой «ИБаркинг», кроме тех, кто реализует «IMammal». – dmigo

+0

Ваша реализация, кстати, написанная, может принимать только «IMammals», а Guard будет делать только «ИБаркинг», поэтому по дизайну он может принимать только лающих млекопитающих, если «Страж» должен что-либо сделать. Если вы хотите, чтобы он принимал все «Ибаркинг», независимо от того, были ли они млекопитающими, вам нужно использовать «ИБаркинг» в конструкторе и выполнить ту же проверку в «Корректировке». Возможно, вам нужно создать более высокий интерфейс, например, «IAlive» или «IFauna», которые могут инкапсулировать как млекопитающих, так и лаять «вещи» (при условии, что все лаки живы). –

ответ

3

Такие упрощенные примеры вряд ли имеют какой-либо смысл. Вам не хватает «проблемного случая» и того, что вы хотите сделать. Покажите класс, который реализует IBarking, но не IMammal и какие проблемы возникают при передаче его Farm. В любом случае, с учетом помещений:

  • Интерфейс IMammal существует.
  • Интерфейс IBarking Существует.
  • Класс, реализующий IBarking, не имеет для реализации IMammal.
  • Конструктор классов Farm должен принять IBarkingиIMammal.
  • Текущий конструктор классов принимает IMammal.

В этом случае вам нужен либо новый конструктор, либо новый частный член, и еще один код для выбора между ними или перекрывающийся интерфейс. Я бы пошел с последним: IFarmable.

Затем вам нужно:

  • public interface IMammal : IFarmable
  • public interface IBarking : IFarmable
  • public Farm(IFarmable farmable) { ... }

Скорее всего у вас есть другие ограничения, как «, но я хочу, чтобы позвонить Eat() по переменной, переданной в конструктор ", но затем ваше описание (" w Предположите, что IBarking всегда IMammal «) неверен или неполный, и вам необходимо переместить Eat() в интерфейс IFarmable.

1

Я попытаюсь истолковать ваш Задание.

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

Лучше дизайн для этого будет:

public class Farm 
{ 
    private readonly IMammal[] _animals; 

    public Farm(IMammal[] animals) 
    { 
     _animals = animals; 
    } 

    public void Feed() 
    { 
     foreach (var animal in _animals) 
      animal.Eat(); 
    } 

    public IBarking GuardingAnimal { get; set; } 

    public void Guard() 
    { 
     if (GuardingAnimal != null) 
      GuardingAnimal .Bark(); 
    } 
} 

Изменения от вашего дизайна:

  1. Я сделал это совершенно ясно, что там может быть охрана животных
  2. охраняемое животное необязательно (поскольку оно назначается через свойство вместо конструктора).

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

Если вы хотите кормить собаку, вы должны сделать этот интерфейс наследованием IMammal (если вы не представите больше возможностей у млекопитающих, в этом случае вам следует извлечь IFeedable или тому подобное).

+0

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

+0

Моя точка зрения заключается в том, что нет общего решения. – jgauffin

Смежные вопросы