Интерфейсы как параметры - PullRequest
4 голосов
/ 02 июля 2010

В каких случаях кто-то передает (или получает) интерфейс в качестве параметра?Это действительно полезная вещь или просто причудливый способ сделать что-то?

Ответы [ 6 ]

18 голосов
/ 02 июля 2010

Это чрезвычайно полезная вещь.

Например, любой из методов расширения LINQ . Они не заботятся о том, что им передано, пока это реализует IEnumerable<T>. Идея состоит в том, что все они могут быть применены ко всему, что вы можете перечислить, используя цикл foreach.

Представьте себе, насколько бесполезным было бы ограничение, если бы все они требовали от вас пропускать, например, T[] массива или List<T> объекта.


Вот только одна очень тривиальная иллюстрация. Давайте представим, что расширений LINQ не существует (что на самом деле вполне реально, если я использую .NET 2.0), и я хочу написать метод Sum.

Я мог бы написать это так:

public static double Sum(List<double> values)
{
    double sum = 0.0;
    foreach (double value in values)
    {
        sum += value;
    }
    return sum;
}

Это все хорошо, но обратите внимание на кое-что здесь: я написал метод для взятия List<double>, который является классом с гораздо большей функциональностью, чем этот код, зависит от . Где он использует Insert? Где он использует RemoveAt? FindAll? Sort? Нет, ничего из этого не требуется. Так действительно ли необходимо , чтобы этот метод получил List<double>?

Более того, скажем, у меня есть double[]. Теоретически, я должен иметь возможность ввести это право в качестве параметра values, так как все, что я делаю, это перечисляю его, используя foreach; но так как я набрал values как List<double>, чтобы передать double[] моему Sum методу, я должен сделать это:

double sum = Sum(new List<double>(myArray));

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

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

5 голосов
/ 02 июля 2010

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

public void MakeNoise(IAnimal animal)
{
  animal.MakeNoise();
}

Мне все равно, какова конкретная реализация, я просто знаю, что все, что передано, я могу вызвать MakeNoise (). Я программирую на интерфейс, а не на реализацию.

public class Dog : IAnimal
{
  public void MakeNoise()
  {
    Console.WriteLine("Woof");
  }
}

public class Cat : IAnimal
{
  public void MakeNoise()
  {
    Console.WriteLine("Meow");
  }
}

Программирование интерфейса является ключевым аспектом ООП, вы найдете его невероятно полезным.

2 голосов
/ 02 июля 2010

Всякий раз, когда вам нужна абстракция.

Один хороший пример - интерфейсы IEnumerable<T> и IQueryable<T> в .NET Framework.Они позволяют вам писать методы расширения, которые можно использовать против List<T>, Dictionary<TKey, TValue> или даже T[].

. Вы также можете, например, использовать Dependency Injection.В ASP.NET MVC обычно используются репозитории для доступа к данным:

public class MyClassRepository
{
    public MyClass GetById(int id)
    {
        // Some Implementation
    }
}

public class MyController
{
    private MyClassRepository _repo;

    public class MyController() : base(new MyClassRepository()) { }

    public class MyController(MyClassRepository repo) { _repo = repo; }
}

Теперь, если вы хотите макетировать этот репозиторий для модульного тестирования ... вы костей.Там нет простого пути.Доступны интерфейсы!

public interface IMyClassRepository
{
    public MyClass GetById(int id);
}

public class MyClassRepository : IMyClassRepository
{
    public MyClass GetById(int id)
    {
        // Some Implementation
    }
}

public class MyController
{
    private IMyClassRepository _repo;

    public class MyController() : base(new MyClassRepository()) { }

    public class MyController(IMyClassRepository repo) { _repo = repo; }
}

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

1 голос
/ 02 июля 2010

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

Например, шаблон Observer или шаблон Proxy , шаблон Visitor и другие. Возможно, вы решите не использовать интерфейс, но я думаю, вы быстро решите, что код становится намного чище (как в более модульном, разделенном по интересам), чем неинтерфейсный код. В этих ситуациях это просто помогает продвигать лучший код.

1 голос
/ 02 июля 2010

Интерфейсы очень полезны.

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

0 голосов
/ 02 июля 2010

Полиморфизм!

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

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