почему интерфейсы создаются вместо их реализаций для каждого класса - PullRequest
0 голосов
/ 10 августа 2011

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

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

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

Ответы [ 4 ]

9 голосов
/ 10 августа 2011

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

Это немного запутано. Интерфейс определяет API, так что куски кода от разных авторов, модулей или проектов могут взаимодействовать. Например, java.util.Collections.sort() может сортировать все, что реализует интерфейс List и содержит объекты, которые реализуют интерфейс Comparable - даже если классы реализации еще не существовали, когда был написан код сортировки!

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

Раньше это активно продвигали сторонники Test-Driven-Development (TDD), которые считают жизненно важным иметь возможность тестировать каждый класс изолированно со всеми его зависимостями, заменяемыми фиктивными объектами. Более старые моделирующие среды могли только моделировать интерфейсы, поэтому, чтобы иметь возможность тестировать каждый класс изолированно, все межклассовые зависимости должны быть через интерфейсы.

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

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

2 голосов
/ 10 августа 2011

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

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

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

1 голос
/ 10 августа 2011

Хорошая индикация для плохого дизайна - это когда у вас есть ISomething или SomethingImpl. Имя интерфейса должно указывать, как его использовать (т. Е. List), а имя класса должно указывать, как оно работает (т. Е. ArrayList).

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

1 голос
/ 10 августа 2011

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

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

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