By Ahmed Orabi
Introduction:
Eclipse development tool provides handy solutions to
refactor the source code while working on the development. Tasks include renaming,
moving different methods between different classes, and even plugins. There is
also an ability to pull up methods to their parent classes. However, this
refactoring does not work well for the cases of abstract classes, especially
when you are working on a large project. This feature works best with quick
uses. This is to be illustrated in the next lines.
Development Requirements:
You must have eclipse development environment. You may
download it from eclipse website:
Scenario:
Create a new package. Name it org.usability.tests.refactoring.employees.
Under this package, create the following classes: AbstractEmploye,
AbstractManager, and TechnicalManager
And this will be the contents for each class:
AbstractEmployee:
public abstract class AbstractEmploye
{
public abstract int[]
getResponsibilities();
public String
getName(){
return "";
}
public int getDepartment(){
return
DepartmentConstants.DEFUALT_DEPARTMENT;
}
public interface
DepartmentConstants {
public int DEFUALT_DEPARTMENT= 0;
public int ARCHIVE_DEPARTMENT= 1;
public int TECHNICAL_DEPARTMENT= 2;
public int MAINTENANCE_DEPARTMENT= 3;
public int MANAGEMENT_DEPARTMENT= 3;
}
public interface
BranchesConstants {
public int MAIN_BRANCH= 0;
public int SECONDARY_BRANCH= 1;
public int STORE_BRANCH= 1;
}
public interface
ResponsibilitiesConstants {
public int MANAGEMENT= 0;
public int MAINTENANCE= 1;
public int REVIEWING= 1;
public int DOCUMENTATION= 1;
}
}
AbstractManager:
public abstract class AbstractManager extends AbstractEmploye
{
public int[]
getResponsibilities(){
return new int[]{ResponsibilitiesConstants.MANAGEMENT, ResponsibilitiesConstants.DOCUMENTATION};
}
public int getDepartment(){
return
DepartmentConstants.MANAGEMENT_DEPARTMENT;
}
}
TechnicalManager:
public abstract class TechnicalManager
extends AbstractManager
{
public int[]
getResponsibilities(){
return new int[]{ResponsibilitiesConstants.MANAGEMENT,
ResponsibilitiesConstants.REVIEWING};
}
public int getDepartment(){
return isMaintenance()?
DepartmentConstants.MAINTENANCE_DEPARTMENT : DepartmentConstants.MANAGEMENT_DEPARTMENT;
}
public int getBranch(){
return this.isLocal()?BranchesConstants.SECONDARY_BRANCH:BranchesConstants.MAIN_BRANCH;
}
public boolean isMaintenance(){
return this.isLocal();
}
public abstract boolean isLocal();
}
Now, I realize I want to pull up the methods isLocal,
isMaintainane, and getBranch from the TechnicalManager class and place them into
its parent AbstractManager. In eclipse, we can just right click on any of these
methods. Let’s say getDepartment, and choose pull up as follows:
Then, in the refactoring wizard you will be informed that
the focused methods are about to be pulled up, which is good):
Hit next, and you will be informed that there is a missing
method and it must be moved along with your getDepartment method, which is a
good usability:
Click Back.and select isMaintainance method since it is
required to avoid any compilation error.
Hit next, but this time you will be informed that there is
still a method to be included, which is isLocal:
Return back and add isLocal. Hit next. This time, you will
be informed that getDepartment already exists and you cannot pull it up:
If we hit finish, we will end up with these errors in
AbstractManager:
Discussion:
The pre-mentioned scenario reveals three major usability
issues. In addition, a neat enhancement is included as follows:
Problem1:
The wizard
can only tell which method is still missing from the method to be pulled up if
it is only referenced by it. However, it does not go through each method to be
included and see if it also has some other references for other methods. For
instance,
Method1 uses Method2. Method2 uses Method3. Method3 uses Method4.
The expectation here is when I try to pull up Method1; I
learn that Method2, Method3, and Method4 must be pulled up as well since they
are referenced together. But what happens here is that we only suggest Method2.
Then, I realize that Method2 needs Method3 and so on.
This problem becomes more complex when you are working on a
large project with more complicated hierarchies.
Problem2:
When I want to pull a method up to a parent Abstract class,
I am expecting this method to become the new parent method to be inherited by
my sub classes. This means that I will expect the abstract getDepartment method
in AbstractManager to be removed because we are going to have an implemented
getDepartment method come from one of its sub-classes. However, what happens
here is eclipse does not recognize it is the same method given and that the
sub-class method is not abstract. The bottom line here is both methods have the
same signature, but we are going to implement that abstract method. However,
this is not the case in eclipse.
Problem3:
Assume that the method getDepartment was not an abstract
method. So, pulling up the sub-class method getDepartment will mean that this
will result in a duplicate method. But in this case, it will be a positive
warning. However, the usability issue I realize here is that after going back
and forth in next/back buttons to include the missing methods I was not able to
pull up the main method from the beginning. The proper usability here is to
inform the user right away that this method already exists in the parent, and
you will have name collisions here.
Enhancement suggestion:
One of the handy solutions we can get when working on
abstract classes, especially for the deeply nested abstract class, is to know
where I would like to put the new abstract method definition. For instance, I
can have the following hierarchy:
Class1
SubClass1
SubClass1SubClass1
SubClass1SubClass1SubClass1
I have a method “someMethod” in the last class in the hierarchy
SubClass1SubClass1SubClass1. I would like to pull it up. I would expect a
wizard to ask me if I would like to make an abstract method. I am given the
chance to decide where I should place it. So, if I said Class1, then it will be
put in Class1, and has its implementation in my end sub class.
This is not only required for abstract classes, but also required
for interfaces.
Conclusion:
The pull-up feature in eclipse is very easy, It provides a
user-friendly wizard, but it needs some work on the abstract classes’ end.
No comments:
Post a Comment