Чтобы сделать ваш код свободно связанным, вот несколько простых вещей, которые нужно запомнить:
Часть 1:
Технически известный как «Разделение концерна». Каждый класс играет определенную роль, он должен обрабатывать бизнес-логику или логику приложения. Старайтесь держаться подальше от класса, который сочетает в себе обе обязанности. т.е. класс, который управляет данными (в широком смысле), является логикой приложения, а класс, который использует данные, является бизнес-логикой.
Лично я называю это (в моем собственном маленьком мире) как create it or use it
. Класс должен создать объект или использовать объект, который никогда не должен делать оба.
Часть 2:
Как осуществить разделение интересов.
Для начала есть два простых метода:
Примечание: шаблоны проектирования не являются абсолютными.
Они должны быть адаптированы к ситуации, но имеют основную тему, которая похожа на все приложения. Так что не смотрите на примеры ниже и говорите, что я должен строго следовать этому; это всего лишь примеры (и слегка надуманные).
Инъекция зависимости :
Здесь вы передаете объект, который использует класс. Объект, который вы передаете, основан на интерфейсе, чтобы ваш класс знал, что с ним делать, но не должен знать фактическую реализацию.
class Tokenizer
{
public:
Tokenizer(std::istream& s)
: stream(s)
{}
std::string nextToken() { std::string token; stream >> token;return token;}
private:
std::istream& stream;
};
Здесь мы вводим поток в токенизатор. Токенайзер не знает, к какому типу относится поток, пока он реализует интерфейс std :: istream.
Шаблон сервисного локатора :
Шаблон локатора службы представляет собой небольшое изменение в зависимости от внедрения. Вместо того, чтобы давать объект, который он может использовать, вы передаете ему объект, который знает, как найти (создать) объект, который вы хотите использовать.
class Application
{
public:
Application(Persister& p)
: persistor(p)
{}
void save()
{
std::auto_ptr<SaveDialog> saveDialog = persistor.getSaveDialog();
saveDialog.DoSaveAction();
}
void load()
{
std::auto_ptr<LoadDialog> loadDialog = persistor.getLoadDialog();
loadDialog.DoLoadAction();
}
private:
Persister& persistor;
};
Здесь мы передаем объект приложения объект персистора. Когда вы выполняете действие сохранения / загрузки, оно использует персистор для создания объекта, который действительно знает, как выполнить действие. Примечание: опять же, персистор является интерфейсом, и вы можете предоставить различные реализации в зависимости от ситуации.
Это полезно, когда potentially
каждый раз при создании экземпляра действия требуется уникальный объект.
Лично я считаю, что это особенно полезно при написании юнит-тестов.
Примечание шаблонов:
Шаблоны проектирования - огромный предмет сам по себе. Это ни в коем случае не исключительный список образцов, которые вы можете использовать, чтобы помочь со слабой связью; это просто общая отправная точка.
С опытом вы поймете, что вы уже используете эти шаблоны, просто вы не использовали их формальные имена. Стандартизируя их имена (и заставляя всех учить их), мы обнаруживаем, что обмениваться идеями легче и быстрее.
managing the data
я имею в виду переменные (не фактические данные). Таким образом, такими вещами, как указатели, нужно управлять, чтобы они не просачивались. Но данные могут быть введены или способ извлечения данных может быть абстрагирован (так что ваш класс может быть повторно использован с различными методами извлечения данных). Извините, я не могу быть более точным.minutae of loose coupling
(люблю это слово мелочи)). Секрет программирования заключается в том, чтобы узнать, когда использовать методы. Чрезмерное использование может привести к путанице кода.Я являюсь разработчиком ASP.NET, поэтому не знаю много о связывании WinForms, но немного знаю о веб-приложениях N-уровня, предполагая 3-уровневую архитектуру приложений UI, Domain, Data Access Layer (DAL).
Слабая связь - это абстракции.
Как утверждает @MKO, если вы можете заменить сборку другой (например, новый проект пользовательского интерфейса, который использует ваш проект домена, новый DAL, который сохраняется в электронной таблице, а не в базе данных), то существует слабая связь. Если ваш домен и DAL зависят от проектов, расположенных ниже по цепочке, связь может быть слабее.
Один аспект чего-то слабо связанного - можно ли заменить объект другим, который реализует тот же интерфейс. Это не зависит от реального объекта, но абстрактное описание того, что он делает (его интерфейс).
Слабая связь, интерфейсы и инжекторы зависимостей (DI) и Inversion of Control (IoC) полезны для изоляции при тестировании.
Например, объект в проекте пользовательского интерфейса вызывает объект репозитория в проекте домена.
Вы можете создать поддельный объект, который реализует тот же интерфейс, что и хранилище, которое использует тестируемый код, а затем написать специальное поведение для тестов ( заглушки для предотвращения вызова производственного кода, сохраняющего / удаляющего / получающего вызов, и макеты, которые действуют как заглушки и отслеживают состояния поддельного объекта в целях тестирования).
Это означает, что единственный вызываемый производственный код теперь находится только в вашем объекте пользовательского интерфейса, ваш тест будет соответствовать только этому методу, и любые неудачные тесты будут изолировать дефект этого метода.
Кроме того, в меню «Анализ» в VS (в зависимости от имеющейся у вас версии) есть инструменты для расчета метрик кода для вашего проекта, одним из которых является Class Coupling, более подробная информация об этом содержится в документации MSDN.
Не получить СЛИШКОМ увязли в minutae рыхлой связи , хотя, если есть НЕТ вероятность того, что вещи , чтобы повторно использовать (например , домен проекта с более чем одним UI) и жизнь продукта мала, то слабая связь становится меньше приоритета (это все равно будет принято во внимание), но все равно это будет обязанность архитекторов / технических руководителей, которые будут проверять ваш код.
источник
источник
Взгляните на 5 твердых принципов. Придерживаясь SRP, интернет-провайдер и DIP значительно снизят связь, DIP, безусловно, является самым мощным. Это фундаментальный принцип ниже уже упомянутого DI .
Также стоит обратить внимание на GRASP . Это странная смесь между абстрактными понятиями (сначала вам будет сложно их реализовать) и конкретными шаблонами (которые на самом деле могут быть полезны), но красота, вероятно, является наименьшей из ваших проблем сейчас.
И наконец, вы можете найти этот раздел по IoC весьма полезным, как отправную точку для общих методов.
На самом деле, я нашел вопрос по stackoverflow , где я демонстрирую применение SOLID для конкретной проблемы. Может быть интересно читать
источник
Согласно Википедии:
Проблема с жесткой связью затрудняет внесение изменений. (Похоже, многие авторы полагают, что это в первую очередь вызывает проблемы во время обслуживания, но, по моему опыту, это относится и к первоначальной разработке.) Что обычно происходит в тесно связанных системах, так это то, что изменение одного модуля в системе требует дополнительных изменений. в модулях, с которыми он связан. Чаще всего это требует больше изменений в других модулях и так далее.
Напротив, в слабо связанной системе изменения относительно изолированы. Поэтому они дешевле и могут быть сделаны с большей уверенностью.
В вашем конкретном примере, средства обработки событий обеспечивают некоторое разделение между графическим интерфейсом и базовыми данными. Тем не менее, это звучит так, как будто есть другие области разделения, которые вы могли бы исследовать. Без подробностей вашей конкретной ситуации сложно быть конкретным. Тем не менее, вы можете начать с 3-уровневой архитектуры, которая разделяет:
Следует учитывать, что для небольших одноразовых приложений с одним разработчиком преимущества принудительной слабой связи на каждом уровне могут не стоить усилий. С другой стороны, для более крупных и сложных приложений с несколькими разработчиками они просто необходимы. Первоначально за внедрение абстракций и обучение разработчиков, незнакомых с кодом, касаются его архитектуры. Однако в долгосрочной перспективе слабое сцепление дает преимущества, которые значительно перевешивают затраты.
Если вы серьезно относитесь к проектированию слабосвязанных систем, ознакомьтесь с принципами SOLID и шаблонами проектирования.
Однако важно понимать, что эти шаблоны и принципы - это просто шаблоны и принципы. Они не правила. Это означает, что их нужно применять прагматично и разумно
Что касается шаблонов, важно понимать, что не существует единой «правильной» реализации ни одного из шаблонов. Они также не являются шаблонами печенья для разработки вашей собственной реализации. Они предназначены для того, чтобы рассказать вам о том, какую форму может иметь хорошее решение, и предоставить вам общий язык для обмена проектными решениями с другими разработчиками.
Всего наилучшего.
источник
Используйте внедрение зависимостей, стратегии и события. В общем: читайте шаблоны проектирования, они все о слабой связи и уменьшении зависимостей. Я бы сказал, что события настолько слабо связаны, насколько это возможно, в то время как для внедрения зависимостей и стратегий требуются некоторые интерфейсы.
Хорошим трюком является размещение классов в разных библиотеках / сборках, и они должны зависеть от как можно меньшего числа других библиотек, что заставит вас проводить рефакторинг для использования меньшего количества зависимостей
источник
Позвольте мне дать альтернативный взгляд. Я просто думаю об этом с точки зрения того, что каждый класс является хорошим API. Порядок вызова методов очевиден. То, что они делают, очевидно. Вы сократили количество методов до необходимого минимума. Например,
init, открыть, закрыть
против
setTheFoo, setBar, initX, getConnection, закрыть
Первый очевиден и выглядит как хороший API. Второй может вызвать ошибки, если вызывается в неправильном порядке.
Я не слишком беспокоюсь о необходимости изменять и перекомпилировать вызывающие. Я поддерживаю много кода, некоторые из которых новые и около 15 лет. Я обычно хочу ошибки компилятора при внесении изменений. Иногда я намеренно нарушаю API по этой причине. Это дает мне возможность рассмотреть последствия для каждого абонента. Я не большой поклонник внедрения зависимостей, потому что я хочу иметь возможность визуально отслеживать свой код без черных ящиков и хочу, чтобы компилятор ловил как можно больше ошибок.
источник