Вопрос

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

void MyBoundaryClass::MyEventHandler(...)
{
  //retrieve stuff from the UI
  //...
  //declare and initialize trasaction to persist
  SimpleTransaction myTransaction(.../*pass down stuff*/);
  //do some other checks
  //...
  //declare transaction persistor
  TransactionPersistor myPersistor(myTransaction, .../*pass down connection to DB and other stuff*/);
  //persist transaction
  try
  {
    myPersistor.Persist();
  }
  catch(...)
  {
    //handle errors
  }
}

Было бы лучше иметь какой-нибудь TransactionManager для переноса объектов SimpleTransaction и TransactionPErsistor?

Есть ли какое-нибудь полезное эмпирическое правило, чтобы понять, нужен ли мне дополнительный уровень инкапсуляции?

На данный момент эмпирическое правило, которому я следую, гласит: "если метод становится слишком масштабным - сделайте что-нибудь с этим".Иногда трудно найти правильный баланс между процедурным и объектно-ориентированным, когда имеешь дело с обработчиками граничных событий.

Есть какое-нибудь мнение?

Ваше здоровье

Это было полезно?

Решение

Учитывая , что:

  • в концепция инкапсуляции речь идет об определении контейнера, и
  • объектно-ориентированный дизайн основан на концепции передачи сообщений (вызов методов).

Я бы сказал, что API является хорошим показателем уместности новой высокоуровневой инкапсуляции (т.е.определение нового объекта)

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

В противном случае, это, вероятно, излишество.

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

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

Но если вы определяете TransactionManager, это дает вам возможность более низкая связь между различными уровнями архитектуры (Графический интерфейс противdata), присутствующий в MyBoundaryClass, и для экспорта управления данными в выделенный класс.
Затем вы можете проверить сохраняемость данных в независимом тестовом сценарии, уделяя особое внимание предельным значениям, сбою базы данных, ненормальным условиям и так далее.

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

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

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

Если вы перегруппируете поведение, иным образом реализованное в нескольких разных местах, в свой TransactionManager, все должно быть в порядке, при условии, что его общедоступный API представляет четкие этапы того, что включает транзакция, а не "информацию о транзакции", как различные служебные функции.Названия самого по себе недостаточно, чтобы судить о сплоченности класса.Необходима комбинация имени и его общедоступного API.

Например, одним интересным аспектом TransactionManager было бы полное инкапсулирование понятия Транзакции, которое бы :

  • станет практически неизвестным остальной части системы и снизит связь между другими классами и "Транзакцией"
  • укрепите согласованность TransactionManager, сосредоточив его API на этапах транзакции (таких как initTransaction(), persistTransaction(), ...), избегая любого средства получения или установки для любого экземпляра транзакции.

Другие советы

Развивая предложение VonC, рассмотрите следующие руководящие принципы:

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

  • Если одна функция (или один объект) предоставляет набор возможностей, которые полезны по отдельности, разумно реорганизовать ее на более мелкие компоненты.

Замечание VonC об API - отличная лакмусовая бумажка:создавать эффективные интерфейсы, и в Объекты часто становятся очевидными.

Уровень инкапсуляции должен быть непосредственно связан с сплоченностью вашего объекта.Ваш объект должен выполнять одну задачу или должен быть разделен на несколько классов и инкапсулировать все его поведение и свойства.

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

Для вас случай, Я бы инкапсулировал с вашей идеей "TransactionManager".Таким образом, "TransactionManager" будет обрабатывать, как работает транзакция, а не "MyBoundaryClass".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top