Слабое связывание и ООП-практики для начинающих

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

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

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

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

Я просто концептуально потерялся в том, как работает этот «лучший способ». Есть предположения?


person Al C    schedule 27.03.2009    source источник


Ответы (4)


Я считаю, что вы пропустили некоторые основные понятия.

Идея ООП начинается с дискретных, повторно используемых логических единиц. С упором на создание самодостаточных модулей.

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

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

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

Похоже, вы действительно спрашиваете о SoC.

Есть много способов достичь SoC. Иногда это требует разделения пользовательского интерфейса, логики обработки и слоев сохраняемости (например, рассмотрим шаблон проектирования MVC). Иногда это просто объединение связанных функций, чтобы уменьшить сложность; что уже делает элемент управления RTF, содержащий все функции, необходимые для управления данными, чтобы у вас не было дополнительных зависимостей.

person NotMe    schedule 27.03.2009

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

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

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

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

person tvanfosson    schedule 27.03.2009
comment
Нет, в Delphi вы, скорее всего, недоработаете - person Stephan Eggermont; 28.03.2009

Что ж, я не совсем понял вопрос, но похоже, что шаблон стратегии здесь сработает.

Создайте объект на основе вашего родительского объекта RTF, но установите методы обработки для хранения и т. д. как определенные объекты с их собственными методами.

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

person jerebear    schedule 27.03.2009

Пример, который вы выбрали, довольно сложен.

Вы правы, когда говорите, что компонент rtf memo очень слабо связан. Настолько слабо, что его практически невозможно расширить, и его можно использовать только как есть, поскольку он объединяет представление/представление, контроллер и модель.

Если вы хотите увидеть пример хорошо спроектированной, расширяемой системы форматированного текста, взгляните на документацию текстовая система OS X (или Gnustep, если вы хотите прочитать код). Это сложно, потому что нужно принять множество проектных решений, которые нужно скрыть от одного модуля к другому. Там можно прямо работать в хорошей структуре.

Компонент rtf memo имеет ограниченную область применения, которую вам, возможно, придется обойти, используя хорошо разработанные классы:

  • Загрузка и сохранение данных компонентов имеет смысл только в том случае, если вам не нужно сохранять другие данные в вашей программе в том же файле/базе данных.
  • Он также плохо обрабатывает большие объемы данных.
  • И он понимает только небольшое подмножество rtf.
person Stephan Eggermont    schedule 27.03.2009