Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Новые технологии в программировании

..pdf
Скачиваний:
10
Добавлен:
05.02.2023
Размер:
5.72 Mб
Скачать

Контрольные вопросы по главе 6

101

 

 

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

В заключение главы хотелось бы дать совет пользователю по использованию CASE (Computer Aided Software Engineering)-средств для построения представленных видов диаграмм:

IDEF — для построения IDEF-диаграмм использовалась программа ERwin Process Modeler. Программа не совсем удобна, однако авторам не удалось найти более удобный редактор для IDEF-диаграмм.

UML — для построения UML-диаграмм, с точки зрения авторов, более удобным является Enterprise Architect фирмы Sparks. Однако есть ещё несколько программных продуктов, которые можно использовать, т. к. они поддерживают последние нововведения текущего стандарта UML, но их поиск мы оставим читателю.

Построение блок-схем — для построения корректных с точки зрения ГОСТа блок-схем авторами не было найдено ни одного специализированного ПО. Ближайшим продуктом для создания блок-схем можно назвать Microsoft Visio, содержащий готовые наборы элементов, приближенных к ГОСТу.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Контрольные вопросы по главе 6

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.В чем разница обозначения циклов в блок-схемах и диаграммах деятельности?

2.Каково назначение терминалов в блок-схемах?

3.В каком порядке наиболее правильно будет составлять UML-диаграммы разрабатываемого продукта?

4.Для описания каких аспектов системы используется IDEF3?

5.Какую роль в диаграммах вариантов использования играют точки расширения?

Глава 7

ТЕХНИКИ НАПИСАНИЯ И ПОДДЕРЖКИ КОДА

В данной главе будет рассмотрен прикладной аспект разработки ПО, а именно — написание кода и проектирование архитектуры программы. Практически все участники команды, вовлеченной в разработку ПО, с ним сталкиваются. В этой главе будут рассмотрены паттерны проектирования ПО — шаблоны, позволяющие «сконструировать» архитектуру программы так, чтобы обеспечить ее гибкость и расширяемость. Также будут представлены «антипаттерны» — яркий пример того, как НЕ надо делать ПО, в основном, они состоят из типичных ошибок начинающих программистов. Так же будут даны некоторые рекомендации по качеству кода, будет рассмотрен рефакторинг и представлены рекомендации по оформлению кода. И конечно, будут рассмотрены инструменты, позволяющие в некоторой степени облегчить и даже автоматизировать написание правильного кода.

7.1 Паттерны проектирования

Разработка объектно-ориентированных программ — чрезвычайно сложное дело. Необходимо проанализировать систему, провести ее декомпозицию, представить систему в виде набора сущностей и определить, каким образом они взаимодействуют друг с другом. Впоследствии именно это мы будем подразумевать под архитектурой программы. Создание архитектуры не представляет сложности в простых проектах, где программа включает в себя 10–20 классов, однако для сложных проектов, в которых могут участвовать от 50 классов, определить их взаимодействие уже проблематично. Архитектура должна в первую очередь соответствовать решаемой задаче, при этом она должна быть достаточно «общей», чтобы впоследствии была возможность добавлять в программу новую функциональность, без изменений (или с минимальными изменениями) существующих модулей. При этом не стоит забывать, что основное преимущество ООП — повторное использо-

7.1 Паттерны проектирования

103

 

 

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

Любой, даже самый опытный, программист скажет, что невозможно с первого раза создать достаточно гибкую и расширяемую архитектуру с возможностью повторного использования отдельных ее модулей. Именно поэтому процесс разработки ПО почти всегда итеративный. Однако чем опытней программист, тем меньше итераций ему необходимо для создания «удачной» архитектуры. Это обусловлено тем, что программист редко начинает разработку с нуля. И это обусловлено не только использованием существующих библиотек, но и тем, что со временем программист находит наиболее «удачные» подходы для обеспечения гибкого взаимодействия сущностей в программе. По сути это и называется паттерном проектирования.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

Канонической книгой с описанием всех паттернов с примерами является [51]. Для более глубокого изучения паттернов проектирования авторы данного учебного пособия советуют обратиться именно к ней. В данном пособии авторы приводят свою интерпретацию паттернов, с упрощенным описанием и примерами, адаптированными для .NET Framework.

Косновным преимуществам шаблонов можно отнести:

снижение сложности проектирования за счет использования готовых абстракций;

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

Однако знание паттернов несет и некоторую опасность:

слепое следование некоторому выбранному шаблону может привести к усложнению программы;

у разработчика может возникнуть желание попробовать некоторый шаблон в деле без особых оснований.

Стоит сказать о классификации паттернов проектирования. Существует ряд так называемых «основных» паттернов, которые могут быть применены при проектировании любой системы независимо от ее специализации, именно им будет уде-

104

Глава 7. Техники написания и поддержки кода

 

 

лено наибольшее внимание. Однако существует множество других, более специализированных, паттернов, например паттерны параллельного программирования, паттерны web-приложений, enterprise паттерны (паттерны проектирования бизнесприложений) и др.

«Основные» паттерны в свою очередь делятся на три группы:

порождающие паттерны предназначены для создания новых объектов в системе;

структурные паттерны решают задачи компоновки системы на основе классов и объектов;

паттерны поведения предназначены для распределения обязанностей между объектами в системе. Из-за ограниченного объёма эти паттерны в дан-

ном учебном пособии не будут рассмотрены. Рекомендуется ознакомиться с ними самостоятельно.

Рассмотрим каждую группу подробнее.

7.1.1 Порождающие паттерны

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Порождающие шаблоны позволяют скрывать реализацию и взаимодействие конкретных классов, существующих в системе. Все что система «знает» об этих классах — интерфейс. Таким образом, порождающие шаблоны обеспечивают большую гибкость при решении вопроса о том, что создается, кем создается, как и когда. Это позволяет собирать системы с различной функциональностью как на этапе компиляции, так и на этапе выполнения.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Абстрактная фабрика.

Абстрактная фабрика — порождающий паттерн проектирования, предоставляющий интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов.

UML-диаграмма паттерна Абстрактная фабрика представлена на рисунке 7.1. Данный паттерн применяется, если:

система не должна зависеть от того, как создаются, компонуются и представляются входящие в нее объекты;

входящие в семейство взаимосвязанные объекты должны использоваться вместе и вам необходимо обеспечить выполнение этого ограничения;

система должна конфигурироваться одним из семейств составляющих ее объектов;

7.1 Паттерны проектирования

105

 

 

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

Рис. 7.1 – UML-диаграмма паттерна Абстрактная фабрика

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

. . . . . . . . . . . . . . . . . . . . . . . . . Пример . . . . . . . . . . . . . . . . . . . . . . . . .

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

При решении этой задачи с помощью паттерна Абстрактная фабрика мы получим следующую архитектуру (рис. 7.2).

Метод SetStyle класса MainWindow выглядит следующим образом:

private void SetStyle(IStyleFactory factory)

106

Глава 7. Техники написания и поддержки кода

 

 

{

_toolbar = factory.GetToolbar(); _button = factory.GetButton();

/*

Инициализация других зависимых компонентов

/*

}

Рис. 7.2 – UML-диаграмма модуля настройки стилей

При таком подходе мы можем полностью изменить визуальную часть программы следующим вызовом:

SetStyle(new MyCustomStyle());

Строитель.

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

UML-диаграмма паттерна Строитель представлена на рисунке 7.3.

Паттерн Строитель отделяет алгоритм пошагового создания сложного объекта от его внешнего представления так, что с помощью одного и того же алгоритма можно получать разные представления этого продукта.

Для этого паттерн Строитель определяет алгоритм поэтапного создания продукта в специальном классе Director (распорядитель), а ответственность за координацию процесса сборки отдельных частей продукта возлагает на иерархию классов Builder. В этой иерархии базовый класс Builder объявляет интерфейсы для построения отдельных частей продукта, а соответствующие подклассы ConcreteBuilder их реализуют подходящим образом, например создают или получают нужные ресур-

7.1 Паттерны проектирования

107

сы, сохраняют промежуточные результаты, контролируют результаты выполнения

операций.

 

Рис. 7.3 – UML-диаграмма паттерна Строитель

 

Преимущества данного паттерна:

позволяет изменять внутреннее представление продукта. Поскольку объект конструируется через абстрактный интерфейс, то для его изменения достаточно определить еще один класс строителя;

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

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

Вцелом данный паттерн похож на Абстрактную фабрику, поэтому необходимо указать их различия — если абстрактная фабрика концентрируется на построении СЕМЕЙСТВА родственных объектов, то Строитель позволяет проводить пошаговое построение ОДНОГО объекта.

. . . . . . . . . . . . . . . . . . . . . . . . . Пример . . . . . . . . . . . . . . . . . . . . . . . . .

Допустим, надо определить процесс построения различных видов домов. Дома отличаются количеством комнат и этажей.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

На рисунке 7.4 представлена UML-диаграмма архитектуры программы, решающей данную задачу.

108

Глава 7. Техники написания и поддержки кода

 

Рис. 7.4 – UML-диаграмма архитектуры программы, позволяющей строить

 

различные виды домов

Далее представлена реализация классов данной архитектуры.

interface IHouseBuilder

{

House GetHouse();

}

class PoorHouse : IHouseBuilder

{

public House GetHouse()

{

var h = new House(); h.BuildFloor(); h.BuildRoom(1); h.BuildRoom(1); h.BuildRoof(); return h;

}

}

class RichHouse : IHouseBuilder

{

public House GetHouse()

{

var h = new House(); h.BuildFloor();

7.1 Паттерны проектирования

109

 

 

h.BuildRoom(1);

h.BuildRoom(1);

h.BuildFloor();

h.BuildRoom(2);

h.BuildRoom(2);

h.BuildFloor();

h.BuildRoom(3);

h.BuildRoom(3);

h.BuildRoof(); return h;

}

}

class HouseDirector

{

public House BuildHouse(IHouseBuilder builder)

{

return builder.BuildHouse();

}

}

class Client

{

private void DoSomething()

{

var director = new HouseDirector();

var richHouse = director.BuildHouse(new RichHouse()); var poorHouse = director.BuildHouse(new PoorHouse());

}

}

Проанализируем данный фрагмент кода. У нас существует абстракция дома (класс House). Также определены 2 строителя, позволяющие строить разные дома — один одноэтажный с двумя комнатами (PoorHouse), второй — трехэтажный с тремя комнатами на каждом этаже. При необходимости создания дома с другими параметрами необходимо только создать новый класс-строитель и определить в нем сборку на основе доступных методов класса House.

Фабричный метод.

Фабричный метод (Factory method, также известен как Virtual constructor) — порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс создавать. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне.

Данный шаблон используется в следующих случаях:

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

класс спроектирован так, что спецификация порождаемого объекта определяется только в наследниках;

110

Глава 7. Техники написания и поддержки кода

 

 

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

На рисунке 7.5 представлена UML-диаграмма данного паттерна.

Рис. 7.5 – UML-диаграмма паттерна Фабричный метод

. . . . . . . . . . . . . . . . . . . . . . . . .

Пример . . . . . . . . . . . . . . . . . . . . . . . . .

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

стовыми файлами. В функции менеджера входит сохранение и загрузка файла. Сто-

ит отметить, что любой текстовый файл может сохраняться различными способа-

ми, например простое сохранение и сохранение с дополнительным кодированием.

При этом необходима возможность работать с различными форматами документов.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Ниже представлена архитектура, иллюстрирующая данную задачу (рис. 7.6).

Рис. 7.6 – UML-диаграмма модуля «менеджер документов»