1. Реализация бизнес-объектов. Классы, инкапсулирующие бизнес-правила, являются основой настоящего объектно-ориентированного программирования. В этой статье мы рассмотрим все аспекты программирования и поставим под сомнение некоторые из наших обычных способов написания программ на Delphi. Основной концепцией этих методов проектирования является инкапсуляция: разработка набора классов с четко определенными интерфейсами (методами), имеющими методы для работы с их свойствами. Эта концепция будет использоваться на протяжении всей программы и окажет сильное влияние на то, как данные сохраняются и представляются. Я хотел бы познакомить читателей со статьей Фрэнсиса Глассбороу о C++. Хотя языки разные, отличные концепции проектирования классов не зависят от языка. Большинство программ, написанных сегодня на Delphi, не являются объектно-ориентированными. Тот факт, что в языке существует объектная модель и используются оригинальные или новые классы, не означает, что программа действительно объектно-ориентирована. Повторное использование кода прекращается, когда сторонние элементы управления перетаскиваются в окна, но взаимозависимости между окнами и модулями быстро множатся. (!!!) Если вы захотите изменить основу программы в будущем (например, переключиться на другую базу данных или перейти от двухуровневой структуры к трехуровневой), это будет серьезно затруднено или дорого. Если программа действительно написана объектно-ориентированным способом, она будет скорее удобной, чем ограничительной. Конечно, написание такой программы требует улучшения концепций, и на начальном этапе наблюдается недостаточная производительность. Большинство команд разработчиков не желают этого делать или рассматривать. Я надеюсь, что в этой статье я покажу вам, как писать лучшие программы. В результате получается система, более надежная, простая в обслуживании, единообразная по стилю, гибкая, допускающая многократное использование и работающая лучше, чем программы, написанные традиционными способами. Программы, код которых ясен и по-настоящему объектно-ориентирован, особенно в случае больших программ, потребуют меньше ресурсов на обслуживание, чем та же программа, написанная традиционным способом. Большая надежность объектно-ориентированных программ обусловлена тем, что данные и операции инкапсулируются в четко определенные классы. Компилятор обеспечивает правильные классы, методы и свойства в коде посредством мощной проверки типов, и не должно быть возможности неправильного понимания цели кода, если будущие изменения повлияют на всю программу. Когда классы используются правильно, отношения между ними говорят сами за себя, и большая часть кода действительно сосредоточена на сути программы, а не на деталях, например, о том, как сохраняются данные. Простота и согласованность кода значительно улучшат удобство сопровождения программы. Как мы увидим, широкое использование наследования классов повышает производительность и надежность, а также повышает согласованность. Эти согласованности отражены в показанном коде, включая поведение классов, способ хранения данных и способ представления данных в пользовательском интерфейсе. Поскольку большая часть функционала предоставляется в базовых классах, можно кардинально изменить программы, быстро изменив их поведение. (Например, интерфейс взаимодействия с пользователем изменен с оконной формы на HTML.) Эти базовые классы могут быть разработаны так, чтобы быть независимыми от программы, так что вторая аналогичная программа сразу же получит прирост производительности. Хороший набор базовых классов может обеспечить значительное улучшение — до 50 % — для скромной программы с точки зрения времени, затрат и надежности. Первое, что следует подчеркнуть, это то, что переход на настоящую объектно-ориентированную разработку — нетривиальный вопрос. В первый раз вы должны убедиться, что вам оказали помощь, или программа небольшая и не имеет срочных сроков поставки; Следует отметить, что объектно-ориентированное (ОО) решение не состоит в том, чтобы диктовать, какие классы следует использовать, а какие классы не следует использовать в программе. Если компания разрабатывает собственные визуальные элементы управления или использует сторонние визуальные элементы управления, базовые классы. Первым шагом при разработке любой объектно-ориентированной программы является рассмотрение того, какие классы необходимы. Это абсолютно принципиальный шаг при условии технических гарантий различных других разработок, поскольку исправление ошибок на ранних этапах будет стоить дорого. При разработке наших классов мы обычно стремимся добиться низкой связанности и высокой связности — классы максимально независимы, но их можно эффективно комбинировать. Один из способов достижения этой цели — разделить классы на разные категории в соответствии с разными ролями, которые они играют в своих программах. Правильный выбор этих ролей приведет к созданию сплоченного набора классов. При разработке роли классов существует единый базовый принцип: разделение обязанностей класса на представление, применение и постоянное хранение данных (обычно в базе данных). Хотя это то же самое, что и разделение трехуровневых программ баз данных, важно отметить, что эта концепция разделения может быть реализована в самых разных средах: от однокристальных программ до распределенных многоуровневых программ. Группа классов, составляющих логику приложения, отвечает за наиболее сложную работу, такую как реагирование на запросы о действиях пользователя и обработку данных. Некоторые классы на этом уровне представляют собой объекты реального мира и моделируются системой. Эти классы часто называют «бизнес-классами» или «классами проблемной области». Они составляют жизненно важную часть любой объектно-ориентированной программы, и поскольку другие классы каким-то образом поддерживают эти классы, они становятся в центре внимания всех разработчиков. Определение того, какие бизнес-объекты присутствуют в конкретной программе, обычно является вопросом опыта и инстинкта, хотя в этом процессе есть целая дисциплина (или искусство?). Преимущества объектно-ориентированной ориентации по сравнению с традиционными методами, такими как SSADM(1), присутствуют. на протяжении всего анализа, проектирования и процесса поддержки сущностей: каждый бизнес-объект может быть представлен посредством объектно-ориентированного анализа (ООА), объектно-ориентированного проектирования (ООД) и объектно-ориентированного программирования (ООП). Позже мы рассмотрим некоторые методы определения подходящих бизнес-целей. Сначала мы предполагаем, что следующие процессы завершены. Взаимосвязь классов между различными уровнями (представление, применение и сохранение) четко определена и взаимосвязана. Отношения между этими классами показаны на рисунке 1. Стрелки на рисунке показывают, что классы одного уровня могут вызывать методы другого класса. На этом рисунке также показано, что классы уровня представления (пользовательский интерфейс) могут управлять уровнем приложения или другими классами пользовательского интерфейса. Уровень приложения (бизнес-объекты) может управлять классами уровня приложения и вызывать методы персистентности. Уровень персистентности отвечает только на запрос уровня приложения. Бизнес-объекты. Чтобы продемонстрировать, как реализуются бизнес-объекты, мы рассмотрим упрощенную программу с сущностями запасов, клиентов и заказов (компания предоставляет определенное количество товаров, а клиенты покупают эти товары). Наш первоначальный анализ показал, что для представления этих объектов необходимы три бизнес-объекта. В нашей программе Delphi будет три класса: TStockItem, TCustomer и Torder. Открытые интерфейсы этих классов показаны в листинге 1. Здесь следует отметить, что характеристики этих классов доступны извне через свойства (PRoperty): это простой и полезный дизайн класса, который контролирует внешний доступ через свойства. Также эти свойства должны находиться в опубликованной области класса (по причинам, которые будут упомянуты позже) и им должны быть присвоены соответствующие значения по умолчанию. Хотя эти уточнения свойств используются только при потоковой передаче классов, они присваивают каждому свойству соответствующее начальное значение и делают код более самоописываемым. First Class Framework На начальных этапах разработки программы мы определили и реализовали три бизнес-объекта. Эти три объекта играют общую роль: каким-то образом представляют объекты реального мира. Поэтому мы хотим, чтобы они имели свойства и соответствующие уровни, аналогичные реальным объектам. Мы дадим каждому объекту общий базовый класс под названием TPDObject (объект предметной области). Со временем мы добавим в этот класс общедоступные методы и свойства, а TPDObject продолжит расширяться. Следует отметить, что TPDObject не должен (никогда) иметь какие-либо элементы, относящиеся к конкретному приложению. Будучи программно-независимым классом, он помещается в независимый модуль и формирует основу инфраструктуры: набор классов, которые можно повторно использовать во многих программах. В будущем наша структура будет значительно расширена за счет формирования базовых классов, которые предоставляют важные программно-независимые функции и могут быть быстро использованы в конкретных системах. Наши TStockItem, TCustomer и Torder — это настроенные объекты для конкретных систем из TPDObject. TMyAppPDObject — это унаследованный класс TPDObject. Хотя его часть реализации пуста, это хорошая демонстрация, если мы добавим определенные элементы в конкретную программу и затронем все проблемные классы в программе, как показано ниже. Иерархия классов должна быть более подходящей. Исходный код фреймворка указан в листинге. Класс TPDObject также предоставляет только идентификатор атрибута, доступный только для чтения, его тип — TobjectID. Этот атрибут присваивает каждому объекту идентификатор: мы будем считать два экземпляра одного и того же типа и идентификатора одним и тем же объектом. Здесь идентификатор намеренно объявлен как отдельный тип, чтобы избежать прямого присвоения значению другого стандартного типа. Тип TobjectID специально не выбирался: здесь я выбрал целое число, которое в некоторых случаях также может быть специализированным классом. Хотя использование классов в качестве идентификаторов кажется более чисто объектно-ориентированным подходом, основанным на том, что классы в нашей предметной области будут создаваться и выпускаться тысячи раз во время работы программы, чтобы избежать дополнительной нагрузки при создании и выпуская объекты, я этого не делал (как пурист, я включаю TobjectID в TPDObject как составной объект). В коде есть пара функций, которые преобразуют строки в наши типы идентификации объектов, а также константа, которая служит начальным значением, когда присваивание не выполняется. Есть много классов, где упоминается идентификация объектов: некоторые говорят, что всем бизнес-объектам должна быть присвоена идентификация (даже GUID), которая не повторяется внутри программы при их создании. Фактически, возможность различать разные объекты в данном контексте — это то, что действительно важно, и сохранение этой простоты будет иметь очевидные преимущества в производительности и пространстве для хранения. Вопросы о спецификациях. Чтобы укрепить некоторые концепции и методы проектирования при разработке фреймворков классов, я задам несколько вопросов и попрошу читателей подумать об основных принципах, лежащих в их основе. Я упоминал, что настоящий объектно-ориентированный дизайн не запрещает использование определенных классов, но есть одно важное исключение. Что это за исключение (ответ на рисунке 1) ((( Листинг 1 — Модуль предметной области, специфичный для приложения (в сокращении) ))) unit IssueDomain;interfaceuses Framework;type TMyAppPDObject = class (TPDObject) end; TStockItem = class ( TMyAppPDObject) имя опубликованного свойства: String; свойство QuantityInStock: кардинальное значение по умолчанию 0; свойство TradePrice: Currency; свойство RetailPrice: Currency; TCustomer = class (TMyAppPDObject) … ; TOrder = class (TMyAppPDObject) … ;implementationend.((( Конец листинга 1 )))((( Листинг 2 — независимый от приложения модуль Framework )))unit Framework;interfaceconst NotAssigned = 0; тип TObjectID = тип TPDObject = частный FID класса: TObjectID; идентификатор публичного свойства: TObjectID чтение FID по умолчанию NotAssigned; end;function StrToID (Значение: String): TObjectID;функция IDToStr (Значение: TObjectID): String;реализация…end.((( Конец листинга 2 )))(1) SSADM (Структурированный системный анализ и системное проектирование) был создан в 1981 г. Веб-сайт Центрального агентства по компьютерным и телекоммуникациям британского правительства (CCTA): http://www.ccta.gov.uk; ) разработал программное обеспечение для анализа и проектирования стандартных методов. Филип Браун — консультант по системному проектированию, активный разработчик, ведущий и тренер. Он будет пропагандировать преимущества эффективных объектно-ориентированных методов для создания более качественных приложений при любой возможности. Вы можете связаться с ним по адресу [email protected].