Подтвердить что ты не робот

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

Из того, что я прочитал, лучше всего использовать классы на основе интерфейса и свободно связывать объекты, чтобы помочь повторно использовать код и unit test.

Правильно ли это правило, которое всегда следует соблюдать?

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

Я использую С# и dot net 2.0, однако считаю, что этот вопрос будет соответствовать многим языкам.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

В этой ситуации вы начинаете намного легче записывать модульные тесты (потому что вы можете иметь заглушки /mocks/fakes для доступа к базе данных и т.д.) и можете использовать IoC для замены компонентов без повторной компиляции ваших приложений.

Ответ 3

Я бы использовал только интерфейсы, где требовался этот уровень абстракции, т.е. вам нужно использовать полиморфное поведение. Обычными примерами могут быть инъекции зависимостей или где у вас есть сценарий типа factory, где-то, или вам нужно установить поведение типа "множественного наследования".

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

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

Ответ 4

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

В качестве примера все объекты потока в .NET получают из System.IO.Stream, который является абстрактным классом. Это упрощает для Microsoft возможность добавления новых функций. В версии 2 frameworkj они добавили свойства ReadTimeout и WriteTimeout без нарушения кода. Если они использовали интерфейс (например, IStream), то они не смогли бы это сделать. Вместо этого им пришлось бы создать новый интерфейс для определения методов тайм-аута, и нам пришлось бы писать код для условного перевода на этот интерфейс, если бы мы хотели использовать функциональные возможности.

Ответ 5

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

Например, в моем приложении CAM у меня есть CuttingPath, связанный с коллекцией очков. Нет смысла иметь интерфейс IPointList, поскольку CuttingPaths всегда будут состоять из точек в моем приложении.

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

Наши приложения поддерживаются с середины 80-х годов и в конце 90-х годов прошли объектно-ориентированный дизайн. Я обнаружил, что то, что может измениться, значительно превысило то, что я изначально думал, и использование интерфейсов выросло. Например, когда-то наш DrawingPath состоял из точек. Но теперь он состоит из объектов (сплайнов, дуг, ec). Поэтому он указывает на EntityList, который представляет собой набор объектов, реализующих интерфейс IEntity.

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

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

Ответ 6

Я попытался взять совет "кода в интерфейс" буквально в недавнем проекте. Конечным результатом было по существу дублирование открытого интерфейса (малый i) каждого класса ровно один раз в реализации интерфейса (большой I). Это практически бессмысленно на практике.

Лучшая стратегия, которую я чувствую, заключается в ограничении реализации интерфейса до глаголов:

Print()
Draw()
Save()
Serialize()
Update()

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

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

Ответ 7

Я согласен с kpollock. Интерфейсы используются для получения общей основы для объектов. Тот факт, что они могут использоваться в контейнерах МОК и других целях, является дополнительной особенностью.

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

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