Почему большинство системных архитекторов настаивают на первом программировании интерфейса?

Это сработало для меня:

ios sdk 9.3

в настройке сборки для допустимой архитектуры app.xcodeproj: armv7 armv7s Build Active architecture: No

Очистите и постройте, сработали для меня.

25
задан Ravindra babu 14 December 2016 в 05:58
поделиться

16 ответов

Программирование на интерфейсе означает соблюдение «контракта», созданного с использованием этого интерфейса. И поэтому, если ваш интерфейс IPoweredByMotor имеет метод start(), будущие классы, которые реализуют интерфейс, будь то MotorizedWheelChair, Automobile или SmoothieMaker, при реализации методов этого интерфейса добавят гибкости вашей системе потому что один кусок кода может запустить двигатель множества различных типов вещей, потому что все, что нужно знать одному коду, - это то, что они отвечают start(). Неважно , как они начинают, просто они должны начинать .

29
ответ дан Brian Warshaw 14 December 2016 в 05:58
поделиться

Существуют некоторые превосходные ответы здесь, но если Вы ищете конкретную причину, посмотрите не далее, чем Поблочное тестирование.

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

interface IRepository<T> { T Get(string key); }

class TaxRateRepository : IRepository<TaxRate> {
    protected internal TaxRateRepository() {}
    public TaxRate Get(string key) {
    // retrieve an TaxRate (obj) from database
    return obj; }
}

Всюду по коду используйте тип IRepository вместо TaxRateRepository.

Репозиторий имеет непубличного конструктора, чтобы поощрить пользователей (разработчики) использовать фабрику для инстанцирования репозитория:

public static class RepositoryFactory {

    public RepositoryFactory() {
        TaxRateRepository = new TaxRateRepository(); }

    public static IRepository TaxRateRepository { get; protected set; }
    public static void SetTaxRateRepository(IRepository rep) {
        TaxRateRepository = rep; }
}

Фабрика является единственным местом, где на класс TaxRateRepository ссылаются непосредственно.

Таким образом, Вам нужны некоторые классы поддержки для этого примера:

class TaxRate {
    public string Region { get; protected set; }
    decimal Rate { get; protected set; }
}

static class Business {
    static decimal GetRate(string region) { 
        var taxRate = RepositoryFactory.TaxRateRepository.Get(region);
        return taxRate.Rate; }
}

И существует также другая другая реализация IRepository - насмешка:

class MockTaxRateRepository : IRepository<TaxRate> {
    public TaxRate ReturnValue { get; set; }
    public bool GetWasCalled { get; protected set; }
    public string KeyParamValue { get; protected set; }
    public TaxRate Get(string key) {
        GetWasCalled = true;
        KeyParamValue = key;
        return ReturnValue; }
}

Поскольку живой код (Бизнес-класс) использует Фабрику для получения Репозитория, в модульном тесте Вы включаете MockRepository для TaxRateRepository. После того как замена сделана, можно трудно кодировать возвращаемое значение и сделать базу данных ненужной.

class MyUnitTestFixture { 
    var rep = new MockTaxRateRepository();

    [FixtureSetup]
    void ConfigureFixture() {
        RepositoryFactory.SetTaxRateRepository(rep); }

    [Test]
    void Test() {
        var region = "NY.NY.Manhattan";
        var rate = 8.5m;
        rep.ReturnValue = new TaxRate { Rate = rate };

        var r = Business.GetRate(region);
        Assert.IsNotNull(r);
        Assert.IsTrue(rep.GetWasCalled);
        Assert.AreEqual(region, rep.KeyParamValue);
        Assert.AreEqual(r.Rate, rate); }
}

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

Дополнительная льгота - то, что можно также выполнить модульный тест без соединения с базой данных, которое делает его быстрее, более портативный (думайте команда мультиразработчика в удаленных местоположениях).

Другая дополнительная льгота - то, что можно использовать процесс Разработки через тестирование (TDD) для фазы реализации разработки. Я строго не использую TDD, но соединение TDD и олдскульного кодирования.

1
ответ дан 14 December 2016 в 05:58
поделиться

Почему простирается зло . Эта статья является прямым ответом на заданный вопрос. Я не могу представить себе почти ни одного случая, когда вам действительно понадобится абстрактный класс , и множество ситуаций, когда это плохая идея. Это не означает, что реализации, использующие абстрактные классы, являются плохими, но вам придется позаботиться о том, чтобы не сделать контракт интерфейса зависимым от артефактов какой-то конкретной реализации (пример: класс Stack в Java).

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

1
ответ дан Eek 14 December 2016 в 05:58
поделиться

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

public void drink (coffee someDrink) {

}

Теперь, допустим, вы хотите использовать точно такой же метод, но передать объект hotTea. Ну, ты не можешь. Вы просто жестко запрограммировали этот метод, чтобы использовать только кофейные объекты. Может быть, это хорошо, может быть, это плохо. Недостатком вышесказанного является то, что он строго блокирует вас одним типом объекта, когда вы хотите передать все виды связанных объектов.

Используя интерфейс, скажем, IHotDrink,

интерфейс IHotDrink {}

и переписав вышеописанный метод для использования интерфейса вместо объекта,

public void drink (IHotDrink someDrink) {

}

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

0
ответ дан Anjisan 14 December 2016 в 05:58
поделиться

Программирование на интерфейсах дает несколько преимуществ:

  1. Требуется для шаблонов типов GoF, таких как шаблон посетителей

  2. Позволяет для альтернативных реализаций. Например, множественные реализации объекта доступа к данным могут существовать для одного интерфейса, который абстрагирует используемое ядро ​​базы данных (AccountDaoMySQL и AccountDaoOracle могут оба реализовывать AccountDao)

  3. Класс может реализовывать несколько интерфейсов. Java не позволяет множественное наследование конкретных классов.

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

  5. В значительной степени используется современными структурами внедрения зависимостей, такими как http://www.springframework.org/ .

  6. В Java интерфейсы могут использоваться для создания динамических прокси - http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Proxy.html . Это может быть очень эффективно использовано в таких средах, как Spring, для выполнения аспектно-ориентированного программирования. Аспекты могут добавить очень полезную функциональность в классы без непосредственного добавления кода Java в эти классы. Примеры этой функциональности включают ведение журнала, аудит, мониторинг производительности, разграничение транзакций и т. Д. http://static.springframework.org/spring/docs/2.5.x/reference/aop.html .

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

20
ответ дан John Vasileff 14 December 2016 в 05:58
поделиться

Вы можете увидеть это с точки зрения perl / python / ruby:

  • когда вы передаете объект в качестве параметра методу, который не передает его тип, вы просто знаете, что он должен ответить на некоторые методы

Я думаю, что рассмотрение интерфейсов Java в качестве аналогии с этим лучше всего объясняет это. Вы на самом деле не передаете тип, вы просто передаете что-то, что отвечает методу (черта, если хотите).

0
ответ дан Geo 14 December 2016 в 05:58
поделиться

Программирование на интерфейсе означает соблюдение «контракта», созданного с использованием этого интерфейса.

Это единственное, что неправильно понимают в интерфейсах.

Нет никакого способа принудить любой такой контракт с интерфейсами. Интерфейсы, по определению, не могут указывать поведение вообще. Классы, где поведение происходит.

1114 Это ошибочное убеждение настолько широко распространено, что многие люди считают его общепринятым мнением. Это, однако, неправильно.

Итак, это утверждение в OP

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

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

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

Это утверждение

Требуется для шаблонов типа GoF, таких как шаблон посетителей

, также неверно. Книга GoF использует абсолютно нулевые интерфейсы, поскольку они не были особенностью языков, используемых в то время. Ни один из шаблонов не требует интерфейсов, хотя некоторые могут их использовать. IMO, паттерн Observer - это тот, в котором интерфейсы могут играть более элегантную роль (хотя в настоящее время паттерн обычно реализуется с использованием событий). В шаблоне «Посетитель» почти всегда требуется базовый класс «Посетитель», реализующий поведение по умолчанию для каждого типа посещаемого узла, IME.

Лично я думаю, что ответ на этот вопрос имеет три аспекта:

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

  2. Java-люди очень сосредоточены на использовании фреймворков, многие из которых (справедливо) требуют классов для реализации своих интерфейсов

  3. Интерфейсы были лучшим способом сделать некоторые вещи до того, как были введены дженерики и аннотации (атрибуты в C #).

Интерфейсы - очень полезная языковая функция, но ими злоупотребляют. Симптомы включают в себя:

  1. Интерфейс реализован только одним классом

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

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

Все эти вещи - запахи кода, ИМО.

4
ответ дан 14 December 2016 в 05:58
поделиться

Я принял бы (с @eed3s9n), что он должен способствовать слабой связи. Кроме того, без интерфейсов поблочное тестирование становится намного более трудным, поскольку Вы не можете копировать свои объекты.

2
ответ дан Danimal 14 December 2016 в 05:58
поделиться
  • 1
    соединение с index_columns и индексами не используется и на самом деле вызывает дублирование столбца; можно также использовать фильтрацию для нахождения только столбцов необходимыми для преобразования (c.collation_name < > @collate) – Kodak 13 May 2014 в 10:01

В одном смысле я думаю, что Ваш вопрос сводится только к, "почему использование взаимодействует через интерфейс и не абстрактные классы?" Технически, можно достигнуть слабой связи и с - конкретная реализация все еще не подвергнута коду вызова, и можно использовать Шаблон "абстрактная фабрика" для возврата конкретной реализации (интерфейсная реализация по сравнению с расширением абстрактного класса) для увеличения гибкости дизайна. На самом деле Вы могли утверждать, что абстрактные классы дают Вам немного больше, так как они позволяют, Вы обоим требуете, чтобы реализации удовлетворили Ваш код ("НЕОБХОДИМО реализовать, запускаются ()"), и обеспечьте реализации по умолчанию ("У меня есть стандартная краска (), можно переопределить, если Вы хотите к") - с интерфейсами, реализации должны быть обеспечены, который со временем может приводить к хрупким проблемам наследования через интерфейсные изменения.

Существенно, тем не менее, я использую интерфейсы главным образом из-за ограничения единичного наследования Java. Если моя реализация ДОЛЖНА наследоваться абстрактному классу, который будет использоваться кодом вызова, который означает, что я теряю гибкость для наследования чему-то еще даже при том, что это может иметь больше смысла (например, для повторного использования кода или иерархии объектов).

0
ответ дан Tom 14 December 2016 в 05:58
поделиться
  • 1
    Я работал в тех же проблемах как pkExec (различия в кодовой странице). Как worarround я использовал следующий сценарий: EXEC sp_msforeachtable "PRINT 'INSERT INTO <new_db_name>.? SELECT * FROM ?;'" и затем выполняемый вставки. Я надеюсь, что это могло помочь кому-то сэкономить некоторое время... – Pecan 15 February 2017 в 15:36

Это - один способ продвинуть свободный связь .

Со слабой связью, изменение в одном модуле не потребует изменения в реализации другого модуля.

А хорошее использование этого понятия Шаблон "абстрактная фабрика" . В примере Википедии интерфейс GUIFactory производит интерфейс Button. Конкретной фабрикой может быть WinFactory (производящий WinButton), или OSXFactory (производящий OSXButton). Вообразите, пишете ли Вы приложение GUI, и необходимо пойти посмотреть вокруг всех экземпляров OldButton класс и изменение их к WinButton. Тогда в следующем году необходимо добавить OSXButton версия.

3
ответ дан Eugene Yokota 14 December 2016 в 05:58
поделиться
  • 1
    @HairyDrumroll, о, я просто изменил, еще раз спасибо – Haseeb 4 March 2019 в 07:26

, Каким образом?

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

, Как Вы знаете все отношения между объектами, которые произойдут в том интерфейсе?

Вы не делаете, и это - проблема.

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

Причины не расширить абстрактный класс:

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

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

Вопросы Вы не спросили:

, Что оборотные стороны использования являются интерфейсом?

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

мне действительно нужно также?

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

Рассматривают классический пример, который LameDuck наследовал от Утки. Звучит легким, не так ли?

ну, который является, пока Вы не должны указывать, что утка была ранена и является теперь Ламе. Или укажите, что неудачник был излечен и может идти снова. Java не позволяет Вам изменять тип объектов, таким образом с помощью подтипов, чтобы указать, что хромота на самом деле не работает.

7
ответ дан Jonathan Allen 14 December 2016 в 05:58
поделиться
  • 1
    Полезный ответ. Прибытие из TFS самостоятельно I' m не убежденный о локальной repo идее - похоже на ненужный дополнительный шаг для выставления изменений в команде. – Andrew Stephens 17 November 2017 в 08:44

Я думаю одна из причин, от абстрактных классов в основном отказались разработчики, могло бы быть недоразумение.

, Когда Банда Четыре записала:

Программа к интерфейсу не реализация.

не было такой вещи как интерфейс C# или Java. Они говорили об объектно-ориентированном интерфейсном понятии, что каждый класс имеет. Erich Gamma упоминает его в это интервью .

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

19
ответ дан Bjorn Reppen 14 December 2016 в 05:58
поделиться
  • 1
    @Zeek2, который - индекс (также названный районом сосредоточения войск) то, где Вы подготавливаете изменения до , они фиксируются. git add изменения этапов (то есть, это добавляет их к индексу); git commit создает новую локальную фиксацию, содержащую все изменения в индексе, и затем очищает индекс (потому что изменения в индексе теперь фиксировались). – Marnen Laibow-Koser 29 April 2019 в 16:02

Большой вопрос. Я отошлю Вас к Josh Bloch в Эффективном Java, который пишет (объект 16), почему предпочесть использование интерфейсов по абстрактным классам. Между прочим, если у Вас нет этой книги, я настоятельно рекомендую его! Вот сводка того, что он говорит:

  1. Существующие классы могут быть легко модифицированы для реализации нового интерфейса. Все, что необходимо сделать, реализовать интерфейс и добавить требуемые методы. Существующие классы не могут быть модифицированы легко для расширения нового абстрактного класса.
  2. Интерфейсы идеальны для определения соединения-ins. соединение А - в интерфейсе позволяет классам объявлять дополнительное, дополнительное поведение (например, Сопоставимый). Это позволяет дополнительной функциональности быть смешанной в с основной функциональностью. Абстрактные классы не могут определить соединение-ins - класс не может расширить больше чем одного родителя.
  3. Интерфейсы допускают неиерархические платформы. , Если у Вас есть класс, который имеет функциональность многих интерфейсов, она может реализовать их всех. Без интерфейсов необходимо было бы создать чрезмерно увеличенную в размерах иерархию классов с классом для каждой комбинации атрибутов, приводящих к комбинаторному взрыву.
  4. Интерфейсы включают безопасные улучшения функциональности. можно создать классы обертки с помощью Шаблона "декоратор", устойчивого и гибкого дизайна. Класс обертки реализует и содержит тот же интерфейс, передавая некоторую функциональность существующим методам, при добавлении специализированного поведения к другим методам. Вы не можете сделать этого с абстрактными методами - необходимо использовать наследование вместо этого, которое более хрупко.

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

23
ответ дан Jonathan 14 December 2016 в 05:58
поделиться

По-моему, Вы видите это так часто, потому что это - очень хорошая практика, которая часто применяется в неправильных ситуациях.

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

  • можно переключить реализации w/o восстанавливающий код, который зависит от интерфейса. Это полезно для: прокси-классы, внедрение зависимости, AOP, и т.д.
  • можно разделить API от реализации в коде. Это может быть хорошо, потому что это делает его очевидным при изменении кода, который будет влиять на другие модули.
  • Это позволяет разработчикам, пишущим код, который зависит от Вашего кода для легкой насмешки API для тестирования.

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

3
ответ дан Jay Stramel 14 December 2016 в 05:58
поделиться
  • 1
    должностное лицо должно использоваться многократно, начиная с него помнят, что последняя возможность заканчивается и возвращает следующую. – Bali Balo 21 July 2012 в 12:13

Все о разработке перед кодированием.

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

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

0
ответ дан James Anderson 14 December 2016 в 05:58
поделиться
  • 1
    Так как я не знаю ни о каких деталях, о которой среде это было сделано, ни один, какая версия SQL Server использовалась, я не могу действительно сказать what' s точная причина. Быстрый поиск на Google, кажется, говорит, что это действительно связано с передачей данных. Here' s, что I' ve, найденный для других, имеющих проблему: dba.stackexchange.com/questions/22010/… или social.msdn.microsoft.com/Forums/sqlserver/en-US/… – David 14 December 2016 в 16:03

Я думаю, что основной причиной использования интерфейсов в Java является ограничение на единичное наследование. Во многих случаях это приводит к ненужным сложностям и дублированию кода. Взгляните на трейты в Scala: http://www.scala-lang.org/node/126 Трейты - особый вид абстрактных классов, но класс может расширять многие из них.

.
0
ответ дан 28 November 2019 в 17:38
поделиться
Другие вопросы по тегам:

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