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

Курсовая работа. Рефакторинг ПО

.pdf
Скачиваний:
139
Добавлен:
05.06.2015
Размер:
817.87 Кб
Скачать

Для незадействованных абстрактных классов используйте «Сворачивание иерархии» (Collapse Hierarchy);

Ненужная делегация может быть удалена с помощью «Встраивания класса» (Inline Class);

Методы с неиспользуемыми параметрами должны быть подвергнуты «Удалению параметров» (Remove Parameter).

Временное поле

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

Временные поля и весь код, работающий с ними следует поместить в отдельный класс с помощью «Выделения класса» (Extract Class);

Удалить условно выполняемый код можно с помощью «Введения объекта Null» (Introduce Null Object) для создания альтернативного компонента.

Цепочка вызовов

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

Для удаления цепочки вызовов применяется прием «Сокрытие делегирования» (Hide Delegate).

Посредник

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

11

Если большую часть методов класс делегирует другому классу, нужно воспользоваться «Удалением посредника» (Remove Middle Man).

Неуместная близость

«Неуместная близость» возникает тогда, когда классы чаще, чем следовало бы, погружены в закрытые части друг друга.

Избавиться от «Неуместной близости» можно с помощью «Перемещения метода» (Move Method) и «Перемещения поля» (Move Field);

По возможности следует прибегнуть к «Замене двунаправленной связи однонаправленной» (Change Bidirectional Association to Unidirectional),

«Выделению класса» (Extract Class) или воспользоваться «Сокрытием делегирования» (Hide Delegate).

Альтернативные классы с разными интерфейсами

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

Применяйте «Переименование метода» (Rename Method) ко всем методам, выполняющим одинаковые действия, но различающимся сигнатурами.

Неполнота библиотечного класса

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

Если надо добавить пару методов, используется «Введение внешнего метода» (Introduce Foreign Method);

Если надо серьезно поменять поведение класса, используется «Введение локального расширения» (Introduce Local Extension).

12

Классы данных

Классы данных это классы, которые содержат только поля и методы для доступа к ним, это просто контейнеры для данных, используемые другими классами.

Следует применить «Инкапсуляцию поля» (Encapsulate Field) и «Инкапсуляцию коллекции» (Encapsulate Collection).

Отказ от наследства

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

Необходимо создать новый класс на одном уровне с потомком и с помощью «Спуска метода» (Push Down Method) и «Спуска поля» (Push Down Field) вытолкнуть в него все бездействующие методы. Благодаря этому в родительском классе будет содержаться только то, что используется совместно.

Комментарии

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

Если для объяснения действий блока все же требуется комментарий, попробуйте применить «Выделение метода» (Extract Method);

Если метод уже выделен, но по-прежнему нужен комментарий для объяснения его действия, воспользуйтесь «Переименованием метода»

(Rename Method);

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

(Introduce Attention).

13

Рефакторинг кода

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

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

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

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

14

Методы рефакторинга

Наиболее употребляемые методы рефакторинга:

Изменение сигнатуры метода (Change Method Signature);

Инкапсуляция поля (Encapsulate Field);

Выделение класса (Extract Class);

Выделение интерфейса (Extract Interface);

Выделение локальной переменной (Extract Local Variable);

Выделение метода (Extract Method);

Генерализация типа (Generalize Type);

Встраивание (Inline);

Введение фабрики (Introduce Factory);

Введение параметра (Introduce Parameter);

Подъем метода (Pull Up Method);

Спуск метода (Push Down Method);

Переименование метода (Rename Method);

Перемещение метода (Move Method);

Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism);

Замена наследования делегированием (Replace Inheritance with Delegation);

Замена кода типа подклассами (Replace Type Code with Subclasses).

Изменение сигнатуры метода

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

Инкапсуляция поля

15

В случае, если у класса имеется открытое поле, необходимо сделать его закрытым и обеспечить методы доступа. После «Инкапсуляции поля» часто применяется «Перемещение метода».

Выделение метода

Выделение метода заключается в выделении из длинного и/или требующего комментариев кода отдельных фрагментов и преобразовании их в отдельные методы, с подстановкой подходящих вызовов в местах использования. В этом случае действует правило: если фрагмент кода требует комментария о том, что он делает, то он должен быть выделен в отдельный метод. Также правило: один метод не должен занимать более чем один экран (25-50 строк, в зависимости от условий редактирования), в противном случае некоторые его фрагменты имеют самостоятельную ценность и подлежат выделению. Из анализа связей выделяемого фрагмента с окружающим контекстом делается вывод о перечне параметров нового метода и его локальных переменных.

Перемещение метода

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

Замена условного оператора полиморфизмом

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

Основные принципы:

Вначале следует создать базовый класс и нужное число подклассов;

В некоторых случаях следует провести оптимизацию условного оператора путем «Выделения метода»;

16

Возможно использование «Перемещения метода», чтобы поместить условный оператор в вершину иерархии наследования;

Выбрав один из подклассов, нужно конкретизировать в нём полиморфный метод базового класса и переместить в него тело соответствующей ветви условного оператора;

Повторить предыдущее действие для каждой ветви условного оператора;

Заменить весь условный оператор вызовом полиморфного метода базового класса.

Проблемы при проведении рефакторинга

Базы данных

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

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

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

Объектные базы данных с одной стороны помогают, но с другой – затрудняют работу. Некоторые объектно-ориентированные БД могут автоматически перемещать данные из одной версии объекта в другую. Это уменьшает трату сил, но все еще занимает часть Вашего времени. Но если

17

такой возможности автоматической миграции данных нет, Вам придется это делать руками, что опять же отнимает много сил. Поэтому здесь нужно быть осторожным: нужно семь раз подумать, прежде чем менять структуру классов. Вы можете легко изменять поведение класса, но при перемещении полей нужно быть осторожным. Нужно использовать временные поля, чтобы создать эффект того, что данные перемещены (но на самом деле они еще пока на месте). А когда Вы полностью уверены, где должны быть данные, Вы их перемещаете окончательно. При этом потребуется изменить только временные поля – это поможет избежать ошибок.

Изменение интерфейсов

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

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

Вы без проблем можете изменить имя метода, если имеете доступ ко всему коду, который вызывает этот метод. Но если этот метод используется каким-то кодом, к которому Вы не имеете доступа, это проблема. Интерфейс, используемый таким кодом, можно назвать общим интерфейсом (т.е. интерфейс, доступный и используемый множеством пользователей, которых Вы, возможно, даже не знаете). Однажды создав такой интерфейс, Вы уже не можете его менять. Здесь уже нужно искать какой-то более сложный способ.

Говоря коротко, при изменении интерфейса Вам придется поддерживать обе его версии: старую и новую. По крайней мере до тех пор, пока все пользователи старого интерфейса не перейдут на новый. Можно сделать так, что старый интерфейс продолжит работать: например, пусть все методы старого интерфейса просто вызывают переименованные методы нового. Заметьте: именно вызывать новый метод из старого, а не копировать код старого метода в новый. Иначе этот код получится в итоге продублированным. При этом, если есть возможность, нужно отметить метод со старым именем устаревшим (в документации или прямо в коде) – так

18

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

Это, конечно, решение, но это в принципе головная боль. Из всего сказанного выше следует, что общие интерфейсы лучше не создавать. А уж если и создаете – то максимально продумывайте его, ведь он создается скорее всего раз и навсегда. Это фундамент, который очень сложно менять потом. А иногда вообще невозможно (попробуйте изменить фундамент 9-ти этажного жилого дома – придется сносить дом).

Изменения проектных решений

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

Когда мы думаем над каким-то проектом, мы имеем в голове (или на листе бумаги… где угодно) несколько вариантов, которые можем использовать для создания этого проекта. И при этом мы должны спрашивать себя: а насколько сложно будет потом изменить эту схему вот на эту? Если кажется, что изменить будет просто, то создаем такое решение, котором может быть и не покрывает всех требований, но простое. А чем проще решение, тем его легче потом изменять. Но если мы не видим простых решений, придется покрепче и подольше подумать над этим (семь раз отмерь

– один раз отрежь). Но сложных решений все-таки нужно избегать.

Когда в рефакторинге нет необходимости

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

19

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

Рефакторинг баз данных

Рефакторинг баз данных (англ. database refactoring) - это простое изменение в схеме базы данных, которое способствует улучшению её проекта при сохранении функциональной и информационной семантики. Иными словами, следствием рефакторинга базы данных не может быть добавление новых функциональных возможностей или ограничение уже существующих, равно как и добавление новых данных или же изменение смысла существующих.

Категории рефакторинга баз данных

Скотт Эмблер и Прамодкумар Садаладж выделяют следующие категории рефакторинга реляционных баз данных:

Рефакторинг структуры

Изменения в структуре таблиц или представлений.

Методы: введение вычисляемого столбца; введение суррогатного ключа; замена данных типа LOB таблицей; замена связи "один ко многим" ассоциативной таблицей; замена столбца; замена суррогатного ключа естественным ключом; переименование представления; переименование столбца; переименование таблицы; перемещение столбца; разбиение столбца; разбиение таблицы; слияние столбцов; слияние таблиц; удаление представления; удаление столбца; удаление таблицы.

Рефакторинг качества данных

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

20