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.
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)
Description: The transformation creates super class(generalization) of an existing class
- 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
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)
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.
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.
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.
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.
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)
!-- *** -->