- •Проектирование информационных систем
- •Вопрос 1. Обязанности, методы, взаимодействия
- •Вопрос 2. Шаблоны
- •Information Expert
- •Шаблон Information Expert
- •Шаблон Creator
- •Шаблон Low Coupling
- •Шаблон High Cohesion
- •Шаблон Controller
- •Вопрос 3. Реализация прецедентов
- •Пример: Реализация прецедентов для данной итерации разработки pos системы тт
- •Проектное решение: makeNewSale
- •Выбор класса-контроллера
- •Проектное решение: enterItem
- •Проектное решение: endSale
- •Проектное решение: makePayment
- •Проектное решение: startup
- •Проектное решение: store-create
- •Подключение уровня интерфейса пользователя к уровню предметной области
Проектное решение: makePayment
Системная операция makePayment выполняется при вводе кассиром внесенной за покупку суммы. Полное описание этой операции:
ОП 4: makePayment
Операция
|
makePayment (amount: Money) |
Ссылки
|
Прецеденты: Оформление продажи
|
Предусловия
|
Инициирована продажа |
Постусловия
|
|
Проектное решение должно обеспечить выполнение постусловий системной операции makePayment.
Создание экземпляра Payment
Одним из постусловий описания операции является следующее:
Создан экземпляр р объекта Payment(создание экземпляра).
При распределении обязанностей, связанных с созданием новых экземпляров, необходимо применять шаблон Creator.
Какой класс записывает, агрегирует, наиболее активно использует или содержит объекты Payment?Одним из кандидатов на выполнение этой обязанности может быть классRegister, поскольку он по логике записывает сведения о платежах. При таком проектном решении сокращается "разрыв между терминологией предметной области и именами программных классов. Еще одним кандидатом может выступать классSale, поскольку он наиболее активно использует информацию объектаPayment.
При определении класса, который должен создавать новые экземпляры, можно также воспользоваться шаблоном Expert. При этом необходимо ответить на вопрос: какой из классов является экспертом в смысле инициализации данных (в данном случае – внесенной суммы)? КлассRegister, выступающий в роли контроллера, получает сообщение о системной операцииmakePayment, поэтому он изначально обладает информацией о внесенной сумме. Следовательно, классRegisterснова является кандидатом на выполнение этой обязанности.
Таким образом, имеем двух кандидатов:
Register
Sale
Это приводит к необходимости применения главной идеи проектирования.
При наличии двух альтернативных вариантов проектирования их следует рассматривать с точки зрения связывания и зацепления, а также, по возможности, будущих изменений. Выбор целесообразно остановить на варианте с хорошими показателями в области связывания и зацепления, обладающем высокой устойчивостью к возможным изменениям в будущем.
Рассмотрим каждый из этих вариантов "с точки зрения" шаблонов HighCohesionиLowCoupling. Если экземпляр объектаPaymentсоздается классомSale, то работа (обязанности) классаRegisterоблегчается. Кроме того, классуRegisterне нужно знать о существовании экземпляраPayment, поскольку он может записывать его опосредованно через объектSale. Это обеспечит низкий уровень связывания объектаRegister. Полученная диаграмма представлена на рис. 3.8.
Рисунок 3.8 – Диаграмма взаимодействия для операции Register-makePayment
Эта диаграмма взаимодействия удовлетворяет постусловиям, приведенным в описании системной операции: создан экземпляр объекта Payment, связанный с объектомSale, и для данного платежа установлено значениеamountTendered.
Регистрация покупки
Сведения о приобретенных покупках должны заноситься в журнал регистрации. Как обычно, если задача не сводится к выбору контроллера или созданию новых объектов (а в данном случае это именно так), при распределении обязанностей необходимо воспользоваться шаблоном Expertи ответить на следующий вопрос:Какой из классов обладает всей информацией о продажах и может выполнять регистрацию?
С точки зрения сокращения разрыва между терминологией предметной области и именами программных классов лучше всего, чтобы всей необходимой информацией обладал объект Store, поскольку он связан с финансовой деятельностью предприятия. В качестве второго варианта можно выбрать класс, реализующий традиционное бухгалтерское понятие, например гроссбухSalesLedger. Однако вводить дополнительные объекты имеет смысл только при достаточном разрастании системы, когда классStoreперестанет обладать свойством зацепления (рис. 3.9).
Рисунок 3.9 – Какой класс должен отвечать за информацию о совершенных покупках?
Заметим, что среди постусловий в описании системной операции упоминается связь объектов SaleиStore. Это пример ситуации, когда постусловие не обязательно нужно реализовывать в проекте. На ранних этапах разработки речь не шла об объектеSalesLedger, однако сейчас стало ясно, что именно его можно использовать вместоStore. После принятия такого решения этот объект нужно будет также добавить в модель предметной области, поскольку его имя соответствует понятию реального мира. Это пример дополнительных исследований и изменений модели предметной области в процессе проектирования, предполагаемый в рамках итеративного подхода к разработке системы.
В данном случае мы будем придерживаться исходного плана и использовать объект Store(рис. 3.10).
Рисунок 3.10 – Регистрация совершенной покупки
Вычисление причитающейся сдачи
Теперь необходимо реализовать процесс вычисления причитающейся сдачи, сумма которой должна отображаться на экране и печататься на чеке. Эта операция выполняется в рамках прецедента Оформление продажи.
Согласно основному принципу шаблона Model-ViewSeparation, сейчас не стоит акцентировать внимание на способе отображения суммы сдачи, однако необходимо убедиться, что эта сумма известна. Заметим, что в настоящее время ни один из классов не обладает такой информацией, поэтому необходимо разработать диаграмму взаимодействия, которая будет обеспечивать выполнение данного требования.
Как обычно, если задача не сводится к выбору контроллера или к созданию новых объектов (а в данном случае это именно так), при распределении обязанностей необходимо воспользоваться шаблоном InformationExpertи ответить на следующий вопрос:Какой из классов отвечает за вычисление суммы сдачи (баланса торговой операции)?
Для вычисления баланса необходимо знать общую стоимость покупки и внесенную покупателем сумму. Следовательно, при решении этой проблемы в качестве частичных экспертов должны выступать классы SaleиPayment.
Если основная обязанность по вычислению баланса возлагается на класс Payment, то для него следует обеспечить видимость классаSale, с помощью которого необходимо получить общую стоимость покупки. Такой подход повышает уровень связывания классов в проекте и не соответствует основному принципу шаблонаLowCoupling.
Если же основная обязанность по вычислению баланса возлагается на класс Sale, то для него следует обеспечить видимость классаPayment, от которого необходимо получить внесенную покупателем сумму. Поскольку классSaleявляется создателем экземпляровPayment, такая видимость уже обеспечена, и данный подход не повышает уровень связывания классов в проекте, что соответствует основному принципу шаблонаLowCouplingи, следовательно, является более предпочтительным.
Таким образом, диаграмма взаимодействия приобретает следующий вид (рис. 3.11).
Рисунок 3.11 – Диаграмма взаимодействия для операции Sale–getBalance