Хороший случай для интерфейсов

Ну, если Вы не намереваетесь ожидать Java 8, надеясь, что они реализуют , лучший API для управления датой и временем, да, использует Joda-разовый . Это - экономия времени, и избегайте многих головных болей.

11
задан Vaccano 26 August 2009 в 15:30
поделиться

17 ответов

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

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

Определение поведения, которое может применяться ко многим различным классам, что позволяет использовать их взаимозаменяемо, даже если между классами нет связи (кроме определенного поведения). Например, Классы Horse и Bicycle могут иметь метод Ride. Вы можете определить интерфейс IRideable, который определяет поведение Ride, и любой класс, использующий это поведение, может использовать объект Horse или Bicycle, не вызывая неестественное наследование между ними.

26
ответ дан 3 December 2019 в 00:38
поделиться

Я не понимаю, откуда это дополнительные накладные расходы.

Интерфейсы обеспечивают гибкость, управляемый код и возможность повторного использования. Кодируя интерфейс, вам не нужно беспокоиться о конкретном коде реализации или логике определенного класса, который вы используете. Вы просто ожидаете результата. Многие классы имеют разные реализации для одной и той же функции (StreamWriter, StringWriter, XmlWriter) .. вам не нужно беспокоиться о том, как они реализуют запись, вам просто нужно вызвать ее.

0
ответ дан 3 December 2019 в 00:38
поделиться

Прошу прощения, так как это не отвечает на ваш вопрос относительно случая для интерфейсов.

Однако я предлагаю попросить человека, о котором идет речь, прочитать ..

Шаблоны проектирования Head First

- Ли

1
ответ дан 3 December 2019 в 00:38
поделиться

Интерфейс объявляет контракт, которому будет придерживаться любой реализующий его объект. Это делает обеспечение качества кода намного проще, чем попытки принудительного применения письменной (не кода) или вербальной структуры, в тот момент, когда класс украшен ссылкой на интерфейс, требования / контракт становятся ясными, и код не будет компилироваться, пока вы не реализовали этот интерфейс полностью и типобезопасен.

Есть много других веских причин для использования интерфейсов (перечисленных здесь), но, вероятно, они не так хорошо резонируют с руководством, как доброе старомодное заявление о «качестве»;)

1
ответ дан 3 December 2019 в 00:38
поделиться

Ну, моя первая реакция такова: если вы объясните, зачем вам нужны интерфейсы, в любом случае это будет нелегкая битва :)

при этом, кроме всех причин, упомянутых выше, интерфейсы - единственный способ для слабо связанного программирования, многоуровневых архитектур, где вам нужно обновлять / заменять компоненты на лету и т. д. - однако по личному опыту это было слишком эзотерической концепцией для руководителя группы архитектуры, в результате чего мы жили в аду dll - не меньше в мире .net!

1
ответ дан 3 December 2019 в 00:38
поделиться

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

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

На ум приходит реализация IDisposable. Ваша команда поместит метод Dispose в класс Object и позволит ему распространяться по системе независимо от того, имеет ли он смысл для объекта или нет.

1
ответ дан 3 December 2019 в 00:38
поделиться

Пожалуйста, простите меня за псевдокод заранее!

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

Где вы могли бы использовать

Widget widget1 = new Widget;

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

public class AnotherObject
{
    public void SomeMethod(Widget widget1)
    {
        //..do something with widget1
    }
}

Мы все еще привязаны к использованию Widget здесь. Но, по крайней мере, это более проверено, поскольку мы можем внедрить реализацию Widget в SomeMethod. Теперь, если бы мы использовали интерфейс вместо этого, мы могли бы еще больше отделить вещи.

public class AnotherObject
{
    public void SomeMethod(IWidget widget1)
    {
        //..do something with widget1
    }
}

Обратите внимание, что теперь нам не требуется конкретная реализация Widget, а вместо этого мы запрашиваем все, что соответствует интерфейсу IWidget. Это означает, что можно внедрить все что угодно, а это значит, что при повседневном использовании кода мы могли бы внедрить реальную реализацию Widget. Но это также означает, что когда мы хотим протестировать этот код, мы можем внедрить поддельный / макет / заглушку (в зависимости от вашего понимания этих терминов) и протестировать наш код.

Но как мы можем пойти дальше. С помощью StructureMap мы можем еще больше отделить этот код. В последнем примере кода наш вызывающий код выглядит примерно так

public class AnotherObject
{
    public void SomeMethod(IWidget widget1)
    {
        //..do something with widget1
    }
}

public class CallingObject
{
    public void AnotherMethod()
    {
        IWidget widget1 = new Widget();
        new AnotherObject().SomeMethod(widget1);
    }
}

Как вы можете видеть в приведенном выше коде, мы удалили зависимость в SomeMethod, передав объект, который соответствует IWidget. Но в CallingObject (). AnotherMethod у нас все еще есть зависимость. Мы также можем использовать StructureMap, чтобы удалить эту зависимость!

[PluginFamily("Default")]
public interface IAnotherObject
{
    ...
}

[PluginFamily("Default")]
public interface ICallingObject
{
    ...
}

[Pluggable("Default")]
public class AnotherObject : IAnotherObject
{
    private IWidget _widget;
    public AnotherObject(IWidget widget)
    {
        _widget = widget;
    }

    public void SomeMethod()
    {
        //..do something with _widget
    }
}

[Pluggable("Default")]
public class CallingObject : ICallingObject
{
    public void AnotherMethod()
    {
        ObjectFactory.GetInstance<IAnotherObject>().SomeMethod();
    }
}

Обратите внимание, что нигде в приведенном выше коде мы не создаем фактическую реализацию AnotherObject. Поскольку все подключено к StructurMap, мы можем разрешить StructureMap передавать соответствующие реализации в зависимости от того, когда и где запускается код. Теперь код действительно гибкий, поскольку мы можем указать через конфигурацию или программно в тесте, какую реализацию мы хотим использовать. Эту настройку можно выполнить «на лету» или как часть процесса сборки и т. Д. Но это не обязательно должно быть где-либо жестко подключено.

[PluginFamily("Default")]
public interface IAnotherObject
{
    ...
}

[PluginFamily("Default")]
public interface ICallingObject
{
    ...
}

[Pluggable("Default")]
public class AnotherObject : IAnotherObject
{
    private IWidget _widget;
    public AnotherObject(IWidget widget)
    {
        _widget = widget;
    }

    public void SomeMethod()
    {
        //..do something with _widget
    }
}

[Pluggable("Default")]
public class CallingObject : ICallingObject
{
    public void AnotherMethod()
    {
        ObjectFactory.GetInstance<IAnotherObject>().SomeMethod();
    }
}

Обратите внимание, что нигде в приведенном выше коде мы не создаем фактическую реализацию AnotherObject. Поскольку все подключено к StructurMap, мы можем разрешить StructureMap передавать соответствующие реализации в зависимости от того, когда и где запускается код. Теперь код действительно гибкий, поскольку мы можем указать через конфигурацию или программно в тесте, какую реализацию мы хотим использовать. Эту настройку можно выполнить "на лету" или как часть процесса сборки и т. Д. Но это не обязательно должно быть где-либо жестко привязано.

[PluginFamily("Default")]
public interface IAnotherObject
{
    ...
}

[PluginFamily("Default")]
public interface ICallingObject
{
    ...
}

[Pluggable("Default")]
public class AnotherObject : IAnotherObject
{
    private IWidget _widget;
    public AnotherObject(IWidget widget)
    {
        _widget = widget;
    }

    public void SomeMethod()
    {
        //..do something with _widget
    }
}

[Pluggable("Default")]
public class CallingObject : ICallingObject
{
    public void AnotherMethod()
    {
        ObjectFactory.GetInstance<IAnotherObject>().SomeMethod();
    }
}

Обратите внимание, что нигде в приведенном выше коде мы не создаем фактическую реализацию AnotherObject. Поскольку все подключено к StructurMap, мы можем разрешить StructureMap передавать соответствующие реализации в зависимости от того, когда и где запускается код. Теперь код действительно гибкий, поскольку мы можем указать через конфигурацию или программно в тесте, какую реализацию мы хотим использовать. Эту настройку можно выполнить «на лету» или как часть процесса сборки и т. Д. Но это не обязательно должно быть где-либо жестко подключено. Теперь код действительно гибкий, поскольку мы можем указать через конфигурацию или программно в тесте, какую реализацию мы хотим использовать. Эту настройку можно выполнить «на лету» или как часть процесса сборки и т. Д. Но это не обязательно должно быть где-либо жестко подключено. Теперь код действительно гибкий, поскольку мы можем указать через конфигурацию или программно в тесте, какую реализацию мы хотим использовать. Эту настройку можно выполнить «на лету» или как часть процесса сборки и т. Д. Но это не обязательно должно быть где-либо жестко подключено.

1
ответ дан 3 December 2019 в 00:38
поделиться

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

1
ответ дан 3 December 2019 в 00:38
поделиться

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

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

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

Например, вы можете создать абстрактный класс со всеми общедоступными абстрактными членами, и это довольно близко к интерфейсу,

2
ответ дан 3 December 2019 в 00:38
поделиться
  • Разработка через тестирование
  • Модульное тестирование

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

2
ответ дан 3 December 2019 в 00:38
поделиться

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

Как вы доказываете, что вам нужны интерфейсы в коде, который вы пишете ваше рабочее место? Найдя место в вашей реальной кодовой базе (не в каком-то коде из чужого продукта и, конечно, не в каком-то игрушечном примере о том, как Duck реализует метод makeNoise в IAnimal), где решение на основе интерфейса лучше, чем решение на основе наследования. Покажите своим начальникам, с какой проблемой вы столкнулись, и спросите, имеет ли смысл изменять правила, чтобы приспособиться к подобным ситуациям. Это' Это поучительный момент, когда все смотрят на одни и те же факты, вместо того, чтобы бить друг друга по голове общими высказываниями и предположениями.

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

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

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

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

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

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

3
ответ дан 3 December 2019 в 00:38
поделиться

Интерфейсы вообще не «требуются», это дизайнерское решение. Я думаю, вам нужно убедить себя, почему в каждом конкретном случае выгодно использовать интерфейс, потому что при добавлении интерфейса есть накладные расходы. С другой стороны, чтобы противостоять аргументу против интерфейсов, потому что вы можете «просто» использовать наследование: у наследования есть свои недостатки, один из них заключается в том, что - по крайней мере, в C # и Java - вы можете использовать наследование только один раз (одиночное наследование); но второй - и, возможно, более важный - заключается в том, что наследование требует от вас понимания работы не только родительского класса, но и всех классов-предков, что затрудняет расширение, но также делает более хрупким, поскольку изменение родительского класса ' реализация может легко сломать подклассы. В этом суть "

3
ответ дан 3 December 2019 в 00:38
поделиться

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

Подумайте о чем-то, что является сериализуемым, на самом деле не имеет смысла (с точки зрения дизайна / моделирования) иметь базовый класс под названием Serializable, поскольку нет смысла говорить, что что-то является сериализуемым. Наличие чего-либо, реализующего интерфейс Serializable, имеет больше смысла, если сказать: «это то, что может делать класс, а не то, что он есть»

4
ответ дан 3 December 2019 в 00:38
поделиться

Для включения модульного тестирования класса.

Для эффективного отслеживания зависимостей (если интерфейс не извлечен и не затронут, возможно, изменилась только семантика класса).

Потому что нет накладных расходов во время выполнения.

Чтобы включить внедрение зависимостей.

... и, возможно, потому что это чертов 2009 год, а не 70-е годы, и дизайнеры современных языков действительно имеют представление о том, что они делают?

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

6
ответ дан 3 December 2019 в 00:38
поделиться

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

Увы. как кто-то сказал

В технологиях преобладают два типа людей: те, кто понимает то, что им не удается, и те, кто управляет тем, чего они не понимают.

10
ответ дан 3 December 2019 в 00:38
поделиться
  • Вы можете реализовать несколько интерфейсов. Вы не можете наследовать от нескольких классов.
  • .. вот и все. То, что другие говорят о разделении кода и разработке через тестирование, не затрагивает суть вопроса, потому что вы можете делать то же самое и с абстрактными классами.
2
ответ дан 3 December 2019 в 00:38
поделиться

Аргумент против них следующий: если класс настроен правильно (с его публичные и частные члены), затем интерфейс - это просто лишние накладные расходы потому что те, кто используют этот класс, ограничено публичными членами. если ты нужно иметь интерфейс, который реализуется более чем 1 классом, тогда просто установите наследование / полиморфизм.

Рассмотрим следующий код:

interface ICrushable
{
  void Crush();
}

public class Vehicle
{
}

public class Animal
{
}

public class Car : Vehicle, ICrushable
{
  public void Crush()
  {
     Console.WriteLine( "Crrrrrassssh" );
  }
}

public class Gorilla : Animal, ICrushable
{
  public void Crush()
  {
     Console.WriteLine( "Sqqqquuuuish" );
  }
}

Имеет ли вообще смысл устанавливать иерархию классов, которая связывает Животные и Транспортные средства, даже если оба могут быть раздавлены моей гигантской сокрушительной машиной? №

18
ответ дан 3 December 2019 в 00:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: