- •Содержание
- •2.3.1. Основные положения
- •2.3.4. Пример выполнения типового задания
- •2.6.1. Обзор методов упрощения условных выражений
- •1.Цель практических занятий
- •2. Основные положения
- •2.1. Тестирование на основе областей эквивалентности и структурное тестирование
- •2.1.1. Области эквивалентности
- •2.1.2. Структурное тестирование. Тестирование ветвей
- •2.1.3. Пример решения типового задания
- •2.2. Модульное тестирование программного обеспечения
- •2.2.1. Общий порядок тестирования по
- •2.2.2. Порядок тестирования классов
- •2.2.3. Пример выполнения типового задания
- •2.3. Интеграционное тестирование программного обеспечения
- •2.3.1. Основные положения
- •2.3.2. Идентификация взаимодействий
- •2.3.3. Выбор тестовых случаев
- •2.3.4. Пример выполнения типового задания
- •2.4. Рефакторинг программного кода. Составление методов
- •2.4.1. Основные идеи рефакторинга программного кода
- •2.4.2. Составление методов
- •2.4.2.1. Выделение метода (Extract Method)
- •Мотивация
- •Техника
- •Использование локальных переменных
- •2.4.2.2. Встраивание метода (Inline Method)
- •Мотивация
- •2.4.2.3. Встраивание временной переменной (Inline Temp)
- •Мотивация
- •Техника
- •2.4.2.4. Замена временной переменной вызовом метода (Replace Temp with Query)
- •Мотивация
- •Техника
- •2.4.2.5. Введение поясняющей переменной (Introduce Explaining Variable)
- •Мотивация
- •Техника
- •2.4.2.6. Расщепление временной переменной (Split Temporary Variable)
- •Мотивация
- •Техника
- •2.4.2.7. Удаление присваиваний параметрам (Remove Assignments to Parameters)
- •Мотивация
- •Техника
- •2.4.2.8. Замена метода объектом методов (Replace Method with Method Object)
- •Мотивация
- •Техника
- •2.4.2.9. Замещение алгоритма (Substitute Algorithm)
- •Мотивация
- •Техника
- •2.5. Рефакторинг программного кода. Перемещение функций между объектами
- •2.5.1. Обзор методов перемещения функций между объектами
- •2.5.2. Перемещение метода (Move Method)
- •2.5.3. Перемещение поля (Move Field)
- •2.5.4. Выделение класса (Extract Class)
- •2.5.5. Встраивание класса (Inline Class)
- •2.5.6. Сокрытие делегирования (Hide Delegate)
- •2.5.7. Удаление посредника (Remove Middle Man)
- •2.5.8. Введение внешнего метода (Introduce Foreign Method)
- •2.5.9. Введение локального расширения (Introduce Local Extension)
- •2.6. Рефакторинг программного кода. Упрощение условных выражений
- •2.6.1. Обзор методов упрощения условных выражений
- •2.6.2. Декомпозиция условного оператора (Decompose Conditional)
- •Мотивация
- •Техника
- •2.6.3. Консолидация условного выражения (Consolidate Conditional Expression)
- •Мотивация
- •Техника
- •2.6.4. Консолидация дублирующихся условных фрагментов (Consolidate Duplicate Conditional Fragments)
- •Мотивация
- •Техника
- •2.6.5. Удаление управляющего флага (Remove Control Flag)
- •Мотивация
- •Техника
- •2.6.6. Замена вложенных условных операторов граничным оператором (Replace Nested Conditional with Guard Clauses)
- •Мотивация
- •Техника
- •2.6.7. Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism)
- •Мотивация
- •Техника
- •2.6.8. Введение объекта Null (Introduce Null Object)
- •Мотивация
- •Техника
- •3. Варианты заданий и порядок выполнения работы
- •Библиографический список
Техника
- Для каждой проверки вставьте граничный оператор. Граничный оператор осуществляет возврат или возбуждает исключительную ситуацию.
- Выполняйте компиляцию и тестирование после каждой замены проверки граничным оператором. Если все граничные операторы, возвращают одинаковый результат, примените «Консолидацию условных выражений» (Consolidate Conditional Expression).
2.6.7. Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism)
Есть условный оператор, поведение которого зависит от типа объекта.
Переместите каждую ветвь условного оператора в перегруженный метод подкласса. Сделайте исходный метод абстрактным.
Исходный код:
double getSpeed() {
switch (_type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() -getLoadFactor()*_numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage); I
throw new RuntimeException ("Should be unreachable”);
}
Диаграмма классов после проведения рефакторинга:
Рисунок 2.10 – Замена условного оператора полиморфизмом
Мотивация
Одним из наиболее внушительно звучащих слов из жаргона объектного программирования является полиморфизм. Сущность полиморфизма состоит в том, что он позволяет избежать написания явных условных операторов, когда есть объекты, поведение которых различно в зависимости от их типа.
В результате оказывается, что операторы switch, выполняющие переключение в зависимости от кода типа, или операторы if-then-else, выполняющие переключение в зависимости от строки типа, в объектно-ориентированных программах встречаются значительно реже.
Полиморфизм дает многие преимущества. Наибольшая отдача имеет место тогда, когда один и тот же набор условий появляется во многих местах программы. Если необходимо ввести новый тип, то приходится отыскивать и изменять все условные операторы. Но при использовании подклассов достаточно создать новый подкласс и обеспечить в нем соответствующие методы. Клиентам класса не надо знать о подклассах, благодаря чему сокращается количество зависимостей в системе и упрощается ее модификация.
Техника
Прежде чем применять «Замену условного оператора полиморфизмом» (Replace Conditional with Polymorphism), следует создать необходимую иерархию наследования. Такая иерархия может уже иметься как результат ранее проведенного рефакторинга. Если этой иерархии нет, ее надо создать.
Создать иерархию наследования можно двумя способами: «Заменой кода типа подклассами» (Replace Type Code with Subclasses) и «Заменой кода типа состоянием/стратегией» (Replace Type Code with State/Strategy). Более простым вариантом является создание подклассов, поэтому по возможности следует выбирать его. Однако если код типа изменяется после того, как создан объект, применять создание подклассов нельзя, и необходимо применять паттерн «состояния/стратегии». Паттерн «состояния/стратегии» должен использоваться и тогда, когда подклассы данного класса уже создаются по другим причинам. Если несколько операторов case выполняют переключение по одному и тому же коду типа, для этого кода типа нужно создать лишь одну иерархию наследования.
После этого можно перейти к рефакторингу условного оператора. Это может быть оператор switch (case) или оператор if.
- Если условный оператор является частью более крупного метода, разделите условный оператор на части и примените «Выделение метода» (Extract Method).
- При необходимости воспользуйтесь перемещением метода, чтобы поместить условный оператор в вершину иерархии наследования.
- Выберите один из подклассов. Создайте метод подкласса, перегружающий метод условного оператора. Скопируйте тело этой ветви условного оператора в метод подкласса и настройте его по месту. Для этого может потребоваться сделать некоторые закрытые члены надкласса защищенными.
- Выполните компиляцию и тестирование.
- Удалите скопированную ветвь из условного оператора.
- Выполните компиляцию и тестирование.
- Повторяйте эти действия с каждой ветвью условного оператора, пока все они не будут превращены в методы подкласса.
- Сделайте метод родительского класса абстрактным.
