Академический Документы
Профессиональный Документы
Культура Документы
On Refactoring
Methods
Report No.10
先端ソフトウェア工学Ⅰ Advanced Software Engineering I
Ahmad EL GHAFARI
ID#1051133
1
1. Extract Method
Suppose I have a software system that collects files found in media (e.g. hard
disk). Starting from selected root directory by user, the system seeks folders,
and sub folders, grabs the files, and then lists them for the user in UI platform.
User can specify whether all files should be listed all just files match particular
category selected. User highlighted that only ZIP, PDF and Executable files
only are of concern.
In case of all files found are listed. User required two features.
¾ User needs to sort (or group) the files matching a particular file type.
¾ User needs to see a list of files filtered by a selected type, i.e. ZIP type
files.
Let’s show the initial class diagram of the system illustrated in Figure 1 File
Collector System Initial Class Diagram
Collector
-m_rootDirectory
-m_collectedFiles: List<File>
-collectAllFiles()
+getCollectedFiles()
+sortCollectedFilesByType()
+filterCollectedFiles()
0..*
File
-m_title
<<enumeration>>
-m_path
FileTypes
-m_fileType
-m_dateCreated +EXECUTABLE
-m_size +PDF
+ZIP
+fileInfo()
+getType()
2
“m_collectedFiles”. Here, I provide Source code of the system defined written
in Java.
Collector.java
public class Collector {
private String m_rootDirectory;
private java.util.List<File> m_collectedFiles =null;
3
Sorting Scenario
files = this.m_collectedFiles.iterator();
while(files.hasNext()){
File file = (File) files.next();
if (file.getType() == FileType.PDF)
result += file.fileInfo();
}
files = this.m_collectedFiles.iterator();
while(files.hasNext()){
File file = (File) files.next();
if (file.getType() == FileType.ZIP)
result += file.fileInfo();
}
return result;
}
As we can see the same code chunk is repeated 3 times. We experience
duplicate code.
Using Extract method that has the algorithm (logical chunk) in one method
and call it in all places required.
public String sortCollectedFilesByType(){
String result="¥nCollected files sorted ¥n";
result+=getFilesSortedAs(FileType.EXECUTABLE);
result+=getFilesSortedAs(FileType.PDF);
result+=getFilesSortedAs(FileType.ZIP);
return result; }
4
The Extracted Method is
private String getFilesSortedAs(
FileType selectedFileType){
String result="";
java.util.Iterator files =
this.m_collectedFiles.iterator();
while(files.hasNext()){
File file = (File) files.next();
if (file.getType() == selectedFileType)
result += file.fileInfo();
}
return result;
}
As we can see the duplicate code was removed preserving the behavior of the
system.
Collector
-m_rootDirectory
-m_collectedFiles: List<File>
-collectAllFiles()
+getCollectedFiles()
+sortCollectedFilesByType()
+filterCollectedFiles()
-getFilesSortedAs()
5
2. Form Template Method
Filtering scenario
After the system listed all files, User chooses a type category from Filter menu.
Then, the system should relist only the files matched the category. User
interested in only three types of files, Executable, PDF and ZIP files.
One can define the method as the following
java.util.Iterator files =
this.m_collectedFiles.iterator();
while(files.hasNext()){
File file = (File) files.next();
if (file.getType() == selectedFileType)
result += file.fileInfo();
}
return result;
}
However, after some time, the developers collected new user requirements.
User raised an issue of the need to filter collected files not only by Type
category, but rather they need to be able to filter the files by file Title, and Size.
Let’s say do this. Copy the method two times changing the parameter for each
to match the criteria. For filtering by title we provide a String selected title,
and the same for size, as the following.
java.util.Iterator files =
this.m_collectedFiles.iterator();
6
while(files.hasNext()){
File file = (File) files.next();
if (file.getTitle().compareTo(selectedTitle)==0)
result += file.fileInfo();
}
return result;
}
java.util.Iterator files =
this.m_collectedFiles.iterator();
while(files.hasNext()){
File file = (File) files.next();
if (file.getSize()==selectedSize)
result += file.fileInfo();
}
return result;
}
It’s obvious how the logic is the same, and what differs is only the parameter
sent via the methods signatures and the condition/checking criteria. This is
only a duplicate in two places. But, suppose some new changes happen to the
system requirements. For example, the system should filter files by
“DateCreated”. In fact, requirements change is open and we need more
abstract way of thinking to enhance extensibility of our system. Form
Template Method can eliminate the duplicate code as the following.
7
Filter class is abstract and have the Template method
Collector
-m_rootDirectory
<<abstract>> -m_collectedFiles: List<File>
Filter 0..* -m_filter: Filter
-collectAllFiles()
<<final>>filter() +getCollectedFiles()
<<abstract>>compare() +sortCollectedFilesByType()
+filterCollectedFiles()
-getFilesSortedAs()
FilterType FilterSize
0..*
<<override>>compare() <<override>>compare() File
<<enumeration>>
-m_title
FileTypes
FilterTitle -m_path
-m_fileType +EXECUTABLE
-m_dateCreated +PDF
<<override>>compare() -m_size +ZIP
+fileInfo()
+getType()
+getTitle()
+getSize()
Filter.java
public abstract class Filter {
abstract Boolean compare(
File file, Object selectedCriteria);
8
final String filterCollectedFiles(
java.util.List<File> collectedFiles, Object
selectedCriteria){
while(files.hasNext()){
File file = (File) files.next();
if (compare (file, selectedCriteria))
result += file.fileInfo();
}
return result;
}
}
FilterType.java
public class FilterType extends Filter{
@Override
Boolean compare(File file, Object selectedCriteria){
Return file.getType().toString().compareTo(
selectedCriteria.toString())==0 ? true:false;
}
}
FilterTitle.java
public class FilterTitle extends Filter {
@Override
Boolean compare(File file, Object selectedCriteria) {
return
(file.getTitle().compareTo(
selectedCriteria.toString())==0)?true:false;
9
}
}
FilterSize.java
public class FilterSize extends Filter{
@Override
Boolean compare(File file, Object selectedCriteria) {
return
file.getSize()==Double.valueOf(selectedCriteria.toS
tring()).doubleValue()?true:false;
}
}
What Happened to the three copies of our filtering method in Class Collector
filterCollectedFiles ()?
Actually, the method and all its duplicates replaced by one just 3 lines, as
following
filter = filterType;
return filter.filter (m_collectedFiles, keyFilter);
}
10
3. Extract Class
Suppose now Customer raised a new requirement. They want the system
not only print out the files information on screen, rather generating XML
log files having information about listed files shown in screen. Also, they
want the system read such XML log files in future. In addition, Customer
wants also to generate log files for some files filtered in specific category
(i.e. all PDF files).
Here, we can add a public method in Collector Class that generates log files
having the list of collected files with their information. And, another
method that reads generated log files. And a method generates a log file
with filtered files according to some category. Here, we can see that with
the first method and third method is the same if we passed the list of files
as an argument to the methods parameters. And, as a result a duplicate
code!
In addition, it turns out that two methods are not enough to do so, unless
we are going to hard-coding or doing procedural programming. Since,
generating an XML file needs creating a file system at storage media, and
needs I/O functionalities, in addition to Serialization procedure and for
reading we need Deserialization. Actually, this is not a job for Class
Collector. In other words, we want to apply Object-Oriented and design
patterns to exhibit clarity, modifiability and extensibility.
Let’s say that all the said amendments are taken and made to Class
Collector. The result is Class Collector is doing too much work, which is a
work that should be done by two classes. Extract Class refactoring
witnesses the birth of a Class that is responsible of doing such kind of job.
This class also needs as an attribute of type File as in Class Collector and
another attribute of type Filter. Here, what we have is two features in two
classes, common attributes, and common methods. In addition, The two
classes Class Filter and Class File will be also aggregated to the new born
Class which is unacceptable coupling in the system architecture that rises
the complexity. The new Class called XMLGenerator.
As shown in Figure 4 The System Class Diagram with the .
11
<<abstract>>
Filter
<<final>>filter()
<<abstract>>compare()
FilterType FilterSize
<<override>>compare() <<override>>compare()
FilterTitle
<<override>>compare()
XMLGenerator
File
-m_collectedFiles: List<File>
-m_title -m_filter: Filter
-m_path
-m_fileType +filterCollectedFiles()
-m_dateCreated +generateXML()
-m_size -serialize()
+readXML()
+fileInfo() -deserialize()
+getType()
+getTitle()
+getSize()
Collector
-m_rootDirectory
-m_collectedFiles: List<File>
-m_filter: Filter
<<enumeration>>
FileTypes -collectAllFiles()
+getCollectedFiles()
+EXECUTABLE
+sortCollectedFilesByType()
+PDF
-getFilesSortedAs()
+ZIP
+filterCollectedFiles()
12
coupling issues among the two said classes and the other two classes Filter
and File. The Extracted Class called FileHandler acts as a superclass for
Collector and XMLGenerator. The common attributes and method will be
moved to the FileHandler As shown in Figure 5.
<<abstract>>
Filter 0..*
<<final>>filter()
<<abstract>>compare()
FilterType FilterSize
<<override>>compare() <<override>>compare()
FilterTitle
<<override>>compare()
File <<abstract>>
FileHandler
-m_title
-m_path #m_filter: Filter
-m_fileType #m_collectedFiles: List<File>
-m_dateCreated +filterCollectedFiles(Object keyFltr, Filter fltrType)
-m_size 0..*
+fileInfo()
+getType()
+getTitle()
+getSize()
Collector
XMLGenerator
-m_rootDirectory
13
FileHandler.java
public abstract class FileHandler {
protected Filter filter =null;
protected java.util.List<File> m_collectedFiles =null;
...
14
System.out.println(
"files were filtered and XML log file was generated
successfully." + "¥n"+s+"¥n")
}
}
The result is one code plays the role for many clients. The features that are
called in many places as needed placed in one place with a newly extracted
class called FileHandler removing the duplicate code, though the solution
introduced might be not the ultimate, but at least showing how Extract Class
refactoring can eliminate duplicate code.
15
4. Pull Up Method
16
References
1. Matrting Folwer, Kent Beck, John Brant, William Opdyke, and Don
Roberts. Refactoring: Improving the Design of Existing Code.
Addison-Wesley, Reading, MA, 1999.
2. Robert France, Sudipto Ghosh, Eunjee Song, and Dae-Kyoo Kim. A
metamodeling approach to pattern-based model refactoring. IEEE
Software, pages 52-58, September 2003.
3. Sami Beydeda, Matthias Book, Volker Grunhn (Eds.). Model-Driven
Software Development. Generic and Domain-Specific Model Refactoring
Using a Model Transformation Engine, Jing Zhang, Yuehua Lin, and Jeff
Gray, pages 199-206, Springer 2005.
17