Какой лучший способ выставить изменчивый интерфейс поверх неизменного? - PullRequest
1 голос
/ 04 мая 2011

Интересно, какова лучшая практика в C # в отношении изменяемых / неизменяемых интерфейсов.

Мне нравится работать только с интерфейсами вместо реальных объектов;удалить зависимости и облегчить тестирование.

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

Вот что я пытаюсь сделать

public interface ISomething
{
    string Name { get; }   
}

public interface IMutableSomething : ISomething
{
    string Name { get; set; }   
}

...

public class ConsumerClass
{
   //Note that I'm working against the interface, not the implementation
   public void DoSomethingOnName(ISomething o)
   {
       var mutableO = (IMutableSomething) o;
       mutableO.Name = "blah";
   }
}

Работая таким образом, я могу легко протестировать ConsumerClass и разорвать любую зависимость между ISomething и его реализацией

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

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

public interface IMutableSomething : ISomething
{
    void SetName(string newName)   
}

or

public interface IMutableSomething // No inheritance, implementation impl. 2 interfaces
{
    string Name { get; set; }
}

Спасибо,

Эрик Г.

Ответы [ 2 ]

0 голосов
/ 04 мая 2011

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

public class ConsumerClass{   
  // Just take IMutableSomething
  public void DoSomethingOnName(IMutableSomething o)   {       
    o.Name = "blah"; 
  }
}

Вызов метода является контрактом, и, как уже говорили другие, вам нужно указать наиболее общий тип, который ваш ConsumerClass может фактически использовать. Возможно, вы захотите ознакомиться с принципом подстановки Лискова: http://en.wikipedia.org/wiki/Liskov_substitution_principle.

В этом случае, хотя IMutableSomething может заменить ISomething, обратное неверно.

0 голосов
/ 04 мая 2011

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

В такой ситуации, если вы ДОЛЖНЫ использовать интерфейс, определите метод set на вашем интерфейсе (или реализуйте свойство по-другому)

public interface ISomething
{
    string Name { get; set;}
    void SetName(string newValue);
}

// Choose one of these methods to implement; both is overkill
public class SomethingElse : ISomething
{
     protected string _internalThing = string.Empty;

     public string Name
     {
         get { return _internalThing; }
         set { throw new InvalidOperationException(); }
     }

     public void SetName(string newValue)
     {
         throw new InvalidOperationException();
     }
}

А затем просто заставьте неизменные интерфейсы ничего не делать со значением (или выдавать исключение).

...