Consider a class C with n methods M1, M2..., Mn.
Let {Ij} = set of instance variables used by method Mj. There are n such sets I1 ,…, In
P = {(Ii, Ij) | (Ii ∩ Ij ) = ∅}
Q = {(Ii, Ij) | (Ii ∩ Ij ) ≠ ∅}
LCOM = (||P| - |Q||)/|P|, if |P| > 0
= 0, otherwise
High LCOM indicate the violation of the Single Responsibility Principle.
Jarchitect (http://www.jarchitect.com/)
NDepend (http://www.ndepend.com/)
This smell arises when members of an abstraction are broken and spread across multiple abstractions (when ideally they should have been localized into a single abstraction).
This smell arises when an abstraction exists that has not been completely decomposed and a further decomposition could reduce its size, implementation complexity, or both.
This smell arises when a supertype and its subtype conceptually do not share an “IS-A” relationship resulting in broken substitutability.
public class Throwable {
// following method is available
// from Java 1.0 version.
// Prints the stack trace as a string
// to standard output
// for processing a stack trace,
// we need to write
// regular expressions
public void printStackTrace();
// other methods elided
}
This smell arises when clumps of data or encoded strings are used instead of creating a class or an interface.
http://www.designite-tools.com
Opdyke introduced the term “Refactoring” and defined as “behavior-preserving program restructuring”
.
According to Fowler“Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code, yet improves its internal structure.”
Better code/design quality leads to improved productivity as well as high morale and motivation of the team
double round_type5(double n)
{
double d,d1,d2,d3;
d=n*100;
d=(int)d/100;
d1= ((d*100) - ((int)d) * 100)/100;
d1+=2.5;
d2= (((int)(d1/5))*5)/100;
d3 = (int)d +d2;
return d3;
}
double roundToNearestPoint05(double number_in)
{
double roundedNo, fractionalPart, roundedFracPart, result;
roundedNo=number_in*100;
roundedNo=(int)roundedNo/100;
fractionalPart= ((roundedNo*100) - ((int)roundedNo) * 100)/100;
fractionalPart+=2.5;
roundedFracPart= (((int)(fractionalPart/5))*5)/100;
result = (int)roundedNo +roundedFracPart;
return result;
}
double round_type5(double n)
{
double d,d1,d2,d3;
d=n*100;
d=(int)d/100;
d1= ((d*100) - ((int)d) * 100)/100;
d1+=2.5;
d2= (((int)(d1/5))*5)/100;
d3 = (int)d +d2;
return d3;
}
void printAppObjects(cInvoice *invoiceObj, list<cItem *> itemContainer)
{
list<cItem*>::iterator itemItr = itemContainer.begin();
while(itemItr != itemContainer.end())
{
cout<<(*itemItr)->getItemName()<<endl;
cout<<(*itemItr)->getItemPrice()<<endl;
cout<<(*itemItr)->getItemTaxes()<<endl;
}
cout<<"Total items:"<<invoiceObj.getItemCount()<<endl;
cout<<"Total amount:"<<invoiceObj.getTotalAmount()<<endl;
cout<<"Total taxes:"<<invoiceObj.getTotalTaxes()<<endl;
}
void printAppObjects(cInvoice *invoiceObj, list<cItem *> itemContainer){
printAllItems(itemContainer);
printInvoiceObj(invoiceObj);
}
void printAllItems(list<cItem*> itemContainer) {
list<cItem*>::iterator itemItr = itemContainer.begin();
while(itemItr != itemContainer.end()) {
cout<<(*itemItr)->getItemName()<<endl;
cout<<(*itemItr)->getItemPrice()<<endl;
cout<<(*itemItr)->getItemTaxes()<<endl;
}
}
void printInvoiceObj(cInvoice *invoiceObj){
cout<<"Total items:"<<invoiceObj.getItemCount()<<endl;
cout<<"Total amount:"<<invoiceObj.getTotalAmount()<<endl;
cout<<"Total taxes:"<<invoiceObj.getTotalTaxes()<<endl;
}
if(itemObj.getAvailableUnits() > requiredUnits &&
itemObj.getExpiryDate()>date() &&
itemObj.getUnitWeight()== requiredUnitWeight)
{
…
}
else
{
…
}
if(isItemSellable(…))
{
…
}
else
{
…
}
int isItemSellable(…) {
return (itemObj.getAvailableUnits() > requiredUnits
&& itemObj.getExpiryDate()>date() &&
itemObj.getUnitWeight()== requiredUnitWeight);
}
switch(angle)
{
case 90:
rotateBy90(…);
break;
case 180:
rotateBy180(…);
break;
}
int rotateBy90(…)
{ …}
int rotateBy180(…)
{… }
rotate(angle);
int rotate(angle, …)
{ …}
It requires the knowledge of the big picture.
Comprehension woes
“Red” values of object-oriented metrics
Design principles
class GraphicsDevice {
public void setFullScreenWindow(Window w) {
if (w != null) {
if (w.getShape() != null) { w.setShape(null); }
if (w.getOpacity() < 1.0f) { w.setOpacity(1.0f); }
if (!w.isOpaque()) {
Color bgColor = w.getBackground();
bgColor = new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 255);
w.setBackground(bgColor);
}
}
…
}
Typically employed to remove “feature envy” smell
A related refactoring is “Move field”
Compile and test
Typically carried out in groups (with fields/methods)
Each abstraction should have a unique responsibility.
In case, an abstraction is changed for multiple causes then it is a multifaceted abstraction (having multiple responsibilities).
Extract-class refactoring splits a multifaceted abstraction into multiple cohesive smaller abstractions.
Compile and test
It may break client’s code