Описание интерфейса .net - PullRequest
3 голосов
/ 07 января 2010

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

Ответы [ 11 ]

9 голосов
/ 07 января 2010

Что такого в интерфейсах?

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

Рассмотрим ситуацию, когда у вас плохо работает код, использующий List<T> в .NET. Если вы используете жесткую реализацию List<T>, есть большая вероятность, что вы нарушите больше кода, изменив реализацию.

Если бы вы использовали IList<T> или IEnumerable<T>, вы могли бы поменять List<T> на LinkedList<T> (или что-либо, реализующее выбранный вами интерфейс) и исправить проблему в одном месте, вместо того, чтобы касаться всех ваших код.

В конце концов ... это примерно Полиморфизм .

3 голосов
/ 07 января 2010

Если бы у вас было два класса, два разных класса уровня доступа к данным с разными реализациями (возможно, SQL Server и CouchDB), то наличие стандартного интерфейса (который они оба реализуют) означало бы, что у вас есть стандартный способ взаимодействия с этими классами .

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

3 голосов
/ 07 января 2010

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

2 голосов
/ 07 января 2010
        foreach (object obj in myArray)
        {
            // distroy all IDisposable objects
            if (obj is IDisposable)
                (obj as IDisposable).Dispose();

            // ends initialization of all ISupportInitialize objects
            else if (obj is ISupportInitialize)
                (obj as ISupportInitialize).EndInit();
        }

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

Это очень полезно при сборе предметов. Вы знаете, что все Животные с (включая человека) могут Есть . Итак, вы знаете, что если в машине есть животные, каждый из них может съесть: Человек , Мышь или Зебра ...

So Interface IEatable :) ...

2 голосов
/ 07 января 2010

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

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

1 голос
/ 07 января 2010

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

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

Школьные проекты ограничены в том, чему они могут научить вас из-за временных ограничений.

0 голосов
/ 07 января 2010

Я могу сделать свой код более тестируемым с помощью интерфейсов.

Если у меня есть ManagerClass

public class PersonManager
{
  public PersonManager(IPersonRepository repository)
  {
    this.Repository = repository;
  }
  private IPersonRepository Repository{get;set;}

  public Person ChangeUsername(string username)
  {
    Person person = this.Repository.GetByUsername(username);
    person.Username = username;
    this.Repository.Save(person);
    return person;
  }
}

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

public class MockPersonRepository : IPersonRepository
{
   public Person GetByUsername(string username)
   {
      return new Person();
   }
   public void Save()
   {}
}

И когда я пишу свой модульный тест, я могу пройти в макете:

[Test]
public void ChangeUserName_NewUsername_ExpectUpdateUsername()
{
  //Arrange
  var manager = new PersonManager(new MockPersonManager());

  //Act
  Person person = manager.ChangeUsername("bob");

  //Assert
  Assert(AreEqual("bob", person.Username);
}

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

0 голосов
/ 07 января 2010

Лучший способ думать об интерфейсе - это контракт между объектом (или службой) и пользователем этой службы. В вашей проблеме с вашим DAL реальное значение интерфейса состоит в том, чтобы иметь возможность заменить класс, который реализует интерфейс, другой реализацией, которая также реализует интерфейс. Допустим, ваша реализация DAL специфична для SQL Server, но теперь вам нужна поддержка MySQL. Вы пишете еще один интерфейс, который взаимодействует с MySQL, подключаете его, и код, использующий DAL, не нуждается в изменении. Преимущество заключается в коде клиента, а не в его реализации.

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

0 голосов
/ 07 января 2010

Проще говоря, интерфейс используется для обеспечения чистой точки разделения между двумя компонентами. Вместо того чтобы проектировать компонент для работы с одним типом (например, List<T>), вы можете проектировать работу с интерфейсом (IList<T>) и работать с любым объектом, реализующим интерфейс.

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

0 голосов
/ 07 января 2010

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

Если у вас есть коллекция IFoo, вы можете вставить любой класс, реализующий IFoo, в эту коллекцию и вызывать один и тот же метод Bar () для каждого из этих объектов. Реализация Bar () может существенно отличаться в каждом классе, который ее реализовал.

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