2.2 First Example
At this point it is
customary to count all the benefits(see section 6.2) of refactorings. Instead,
we would like to continue with an example which will show the practical use of
refactorings. This example is a part of
the DPT-tool and can be performed by users.
For the description of a transformation in examples, the following
scheme will be used:
- Name and short information
about transformation
- Start- and end- state
(UML-diagram)
- Actual parameters of
transformation
Note: For a complete definition and preconditions of each
transformation see chapter 4
2.2.1 Program description
The welcome-program is a
simple car-lifecycle simulation program written in Java. It creates a BMW3 car
with BMW3 tires and a BMW3 engine, and lets this car drive until the car is a
wreck. During the drive, the tires are rotated and changed and the engine is
replaced. This program works only for a BMW3 car.
-
Program-files(see appendix C):
AppMain.java - Contains main
function, creates and runs a new application frame.
AppFrame.java - Class contains
GUI-Components. Creates and drives a BMW-3 car.
Car.java - Class Car(BMW3) contains tires and engine and calls to their
methods
HelpBox.java - Dialog that
displays help-information.
BMW3_Tire.java - Contains concrete class tire for a BMW3 car
BMW3_Engine.java - Contains concrete class engine for a BMW3 car
-
New requirements for car-simulator:
a) Next the BMW3 will be built with a new type of engine/tire (Program
extension)
b) A manager decides to use this program to simulate other cars.(Reuse
of the program)
2.2.2 Step by step
transformations
First we will make the
program more flexible and easily extendible (e.g. for adding new types of
tires/engine), and finally reuse this program(for a new type of car).
Step1:
Generalize class
The transformation creates a super-class for a given class.
Motivation:
Generalization of concrete
Car-parts. New generalized parts have the same interface as concrete parts to
the class Car. This is important to make
the program more flexible (e.g. application could use other concrete parts as
implementation of generalized parts).
Concrete classes BMW3_Engine and BMW3_Tire will be
generalized. New generalized class CarEngine / CarTire will be created
and BMW3_Engine / BMW3_Tire extends those
classes.
(Figure 2.1 Example: class-generalization)
Name: Generalization
Description: The transformation creates super class(generalization)
of an existing class
Parameters:
- New class(Super) ="CarEngine"; modifier="public";
option=create constructor
- Class for generalization(Subclass)
="BMW3_Engine";
- Methods and variables to move to new super-class
The same transformation needs to be done with class BMW3_Tire
Step2: Substitute members of a class
The transformation changes
the type of variable/method(method-parameters) from class to super class
Motivation:
The class Car will use
generalized parts instead concrete BMW3 parts. This makes the program more
flexible because the class Car is no longer dependent on
concrete parts and it can operate with any Car tire and Car engine. (Note: The
application still builds cars with concrete BMW3-Tire and BMW3-Engine.)
This is a two step
refactoring:
- Substitute
class-variable: Type of car-variables
engine/tires changes to the super-class.
- Substitute constructor :
car-constructor will use generalized engine and tires as parameters
(Figure 2.2 Example: substitute members )
a) Substitute variable
Name: Substitute type
of the variable.
Description: Transformation
changes the type(=class) of variable to its super class.
Parameters: Car variables for
Engine and Tire
b) Substitute method-parameters
Name: Substitute
parameters of the method.
Description: Transformation
changes the type(=class) of parameters to its super class.
Parameters: Constructor-method
of class Car
The transformation creates new factory-class(or adds factory method to
existing class)
Motivation :
The application still builds cars with concrete parts. Next a factory
will be created to build engine and tires. This step makes the program easily
extendible(e.g. by change of only one factory method we can build a car with,
for example, a new type of engine).
This is also a two step refactoring:
- Create/add concrete factory for BMW3 cars: factory creates BMW3-
engine and tires
- Substitute type of create-methods: factory will build generalized
engine and tires
(Figure 2.3
Example: create factory)
a) Create/Add
factory
Name: Create factory
/ Add factory method
Description: Transformation
creates/uses a factory and creates a factory-method.
Parameters: Name of the
factory=BMW3_Factory; option
=create constructor
Create-method
name =Make_engine
Class to be created=BMW3_Engine; constructor to be used
=default
The same transformation needs to be done with class BMW_Tire, but this time
for the existing factory(Transformation=Add factory method).
b) Substitute type
of the method
Name: Substitute type
of the method
Description: Transformation
changes the type(=class) of the method to its super class
Parameters: BMW3_Factory methods MakeEngine and MakeTire
Step
4: Create interface for a class
The transformation creates an interface for an existing class.
Motivation:
The BMW3 factory creates
parts for the BMW3 car. Now we can generalize this factory to interface Car_Factory, that can be
used in the future to build a new car-type. Any implementation of this interface will build a car that is
suitable for this application. This step makes the program more extendable.
(Figure
2.4 Example: create interface)
Name: Create
interface.
Description: Transformation
creates an interface for the existing class.
Parameters: New interface
name Car_Factory;
modifier="public"
Implementor name BMW3_Factory; Implementor
methods for interface.
Step
5: Create instance variable for a class
The transformation creates an instance variable of an existing class.
Motivation:
Application gets the
factory-variable that will build a car. This makes the program more flexible
because the application is no longer responsible for the creation of the
car-parts.
This is a two step refactoring:
- Create new member (new
variable with type = BMW3_Factory)
- Substitute type(=class) of
variable to its super class(e.g. interface Car_Factory)
(Figure 2.5
Example: create instance)
a) Create instance
variable
Name: Create new
variable.
Description: Transformation
creates a variable with default initialization
Parameters: Class name =AppFrame New
variable name =oFactory;
Type of new
variable=BMW3_Factory
b)
Substitute variable
Name: Substitute the type of the variable.
Description: Transformation changes the type(=class) of variable to its
super class
Parameters: variable oFactory for class AppFrame
Step
6: Reassociate (App will use
Car_Factory to build a Car)
Transformation replaces the
creation of a class with create-method of its factory class.
Motivation:
So far the application calls
car-constructor and passes concrete BMW3-parts in order to create a car. Now
application will use factory to create those parts. This step finalizes the
modifications completed by step 4 and step 5 .
Description: Transformation replaces the current
method-parameters with a call to a factory-method.
Parameters: Application-class
=AppFrame, Factory-member =oCarFactory.
2.2.3 Benefits
The source code
modifications completed by step1 to step 6 didnt change the functionality of
the program. The program will build and drive the BMW3 cars as good as before.
But the program is now more flexible and the extension of this program can be
done on the fly:
- Other tires or engines can be added.
(e.g. Transformation: "Specialize" can create new subclasses
of generalized tire /engine)
(Figure 2.7 Example: extend classes)
-
Switching the tires and engines for a car can be done by modification
of only one factory-method
(Figure 2.8 Example: switch class)
- Other factories can be added to create other cars (e.g.
Transformation: "Implements" can create new implementations of interface
"Car_Factory")
- Application can be reused by the use of other car-factory
(Figure 2.9 Example: reuse of application)