Я думаю, что что-то упустил в концепции «Программирование на интерфейс» - PullRequest
1 голос
/ 20 ноября 2010

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

public Interface ISomeInterface
{
  //some methods/properties
}

public class FooClass : ISomeInterface
{
  //implemented ISomeInterfaces methods/properties
}

И вы используете этот объект класса в реализации где-то в вашей программе

public class BarClass 
{
  private ISomeInterface _someInterface;
  public BarClass(ISomeInterface someInterface)
  {
    _someInterface = someInterface;
  }
  //rest of class
}

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

public class BarClass 
{
  private FooClass _fooClass;
  public BarClass(FooClass fooClass)
  {
    _fooClass = fooClass;
  }
  //rest of class
}

Чего мне не хватает, чтобы понять это? Я не думал, что буду непосредственно объявлять объекты интерфейса?

Заранее спасибо.

Ответы [ 6 ]

7 голосов
/ 20 ноября 2010

Идея состоит в том, что BarClass не должен быть тесно связан с конкретной реализацией ISomeInterface.

Если вы используете это:

public BarClass(FooClass fooClass)

, это означает, что BarClass можетработать только с этой конкретной реализацией FooClass и ничего больше.Принимая во внимание, что если вы используете:

public BarClass(ISomeInterface fooClass)

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

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

1 голос
/ 20 ноября 2010

Предположим, что FooClass записал что-то в базу данных. Вы хотите протестировать BarClass, не устанавливая базу данных. Если вы создали другой TestFoo, в котором реализован тот же интерфейс, вы можете притвориться базой данных и более легко протестировать свой класс; BarClass не должен был знать, что он не разговаривал с «настоящим» FooClass.

0 голосов
/ 21 ноября 2010

Другой способ думать о взаимодействии между интерфейсами и классами - перевернуть их с ног на голову. Это значит начать с занятий в первую очередь. Допустим, у вас есть несколько классов, которые предоставляют метод с именем "Sort ()". Затем у вас есть другой класс, у которого есть метод, который требует ссылки на эти классы и в свою очередь вызывает их методы "Sort ()". Вместо нескольких методов с разными параметрами вы можете создать и присоединить интерфейс к этим классам (это очень быстро исправить, поскольку эти классы уже содержат реализацию).

 A.Sort()
 B.Sort()
 C.Sort()

 interface ISortable {void Sort();}
 A : ISortable
 B : ISortable
 C : ISortable

 D.SortSomething(ISortable foo)
 {
      foo.Sort()
 } 

Может быть, это слишком абстрактно. Мое любимое использование интерфейсов - позволить моим классам участвовать в циклах foreach.

 class SomeCollection : IEnumerable
 {
      List<SomeItem> _items = new List<SomeItem>();

      // This is the only code I need to enable this class to participate in foreach loop.
      public Enumerator GetEnumerator()
      {
            return _items.GetEnumerator();
      }
 }

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

0 голосов
/ 20 ноября 2010

Одним из основных преимуществ программирования на ISomeInterface вместо FooClass является то, что вы, вероятно, можете изменить свою реализацию FooClass. Например, рассмотрим приложение для блога на основе базы данных:

interface IBlogStorage{
    getPosts();
}

тогда у вас есть такой класс:

class XMLBlogSotrage: IBlogStorage{}

и предположим, что вы все внедрили в интерфейс. позже вы думаете, что XML слишком медленный и хотите использовать RDBMS, тогда:

class MsSQLBlogStorage:IBlogStorage{}

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

0 голосов
/ 20 ноября 2010

Используя определение интерфейса вместо конкретной реализации, ваш код теперь более слабо связан. Этот метод используется для внедрения зависимостей.

Кроме того, это удобно, когда вам нужно реализовать FooClass по-другому. Если вы использовали конкретную реализацию, вам нужно будет вносить изменения в код, где бы вы ни объявили FooClass. Программирование на основе интерфейса защищает вас от последствий таких изменений.

0 голосов
/ 20 ноября 2010

Есть ли у вас C / C ++ фон?Тогда вы должны знать, что

private ISomeInterface _someInterface;

будет написано как

private:
  ISomeInterface& _someInterface;

в C ++ (при условии, что у вас есть абстрактный базовый класс ISomeInterface).

Это означаетвы храните ссылку на объект, реализующий ISomeInterface, а не на сам объект.Преимущество этого состоит в том, что вы можете передавать ЛЮБОЙ объект в BarClass, который реализует ISomeInterface, что дает вам большую гибкость, например, для модульного тестирования.

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