1.搬移方法
搬移方法:当A类中出现了多次调用某个对象的方法时,则可以将该对象的方法写在A类中.或者某个方法被多个类调用时,此时看哪个类的数据与该方法联系更多,这件该方法移到该类—–称之为代码情节(Feature Envy)。
eg:
class BankAccount
{
private int age;
private int credit;
public BankAccount(...){...};
public double calculateRate()
{
if (credit>1)
return 0.3;
if (age>18)
return 0.4;
return 0.5;
}
}
class AccountInterest
{
private BankAccount account;
public double getRate()
{
return account.calculateRate();//calculateRate方法被调用一次
}
public boolean isNormalRate()
{
return (account.calculateRate==0.5);//calculateRate方法在被调用
}
}
重构:将calculateRate方法移到AccountInterest里去
class AccountInterest
{
private BankAccount account;
public double calculateRate()
{
if (account.credit>1)
return 0.3;
if (account.age>18)
return 0.4;
return 0.5;
}
}
提升方法:是指多个子类用到的方法提升到父类中声明
注意:如果不是每个子类都用到该方法,可以考虑用接口,或其他方式
eg: turn 方法在 Motor,Bus子类中都用到,可以将turn方法移到父类Car中申明
abstract class Car{}
class Motor extends Car{
public void turn (Direction direct){....};
}
class Bus extends Car{
public void turn (Direction direct){...};
}
enum Direction{
left,right;
}
重构: turn方法移到父类中
abstract class Car{
public abstract void turn(Direction direct);
}
enum Direction{
left,right;
}
降低方法:如果父类的方法在父类中联系不大,且适合子类使用,则将父类中的方法移到子类中。
eg:
abstract class Animal
{
public void bark();
}
class Dog extends Animal
{
}
重构:
abstract class Animal{}
class Dog extends Animal
{
public void bark(){};
}
2.搬移字段
提升字段:多个子类中用到的字段可以提升到父类中。
降低字段:把基类中只有某些少数类用到的字段降低到使用它们的子类中
注意:搬移方法时,要先搬移相关的字段,再搬移方法。
Self Encapsulate(自我封装):对某个字段设置setter和getter方法,让其他方法通过方法访问该字段。
private double interestRate;
public double interestForAmount_Days(int amount,int days)
{
return getInterestRate()*amount*days/365;
}
public void setInterestRate(int arg)
{
interestRate=arg;
}
public double getInterestRate()
{
return interestRate;
}
3.类与类的联系
使用委派代替继承:当A类与B类之间不存在父子类等的硬关系,即联系不大时,可以采用委派机制代替继承即B类对象以成员变量存在A类中使用。
提取接口:当A类中只使用到B类中的几个成员变量或方法,可以将B类抽象出一个接口,接口中定义了使用到的方法,让A类调用。
4.方法重构
抽取方法:某些计算复杂的过程按照功能提取成各个小方法,这样就可以使代码的可读性、维护性得到提高。即将一个长代码的方法分解出多个方法,并由其调用即可,对长的代码可以分解成几个步骤。
注意:方法重构时要考虑传入什么参数和返回什么参数。
eg:有个CalculateGrandTotal()的长方法
class Receipt
{
private List<decimal> discounts;
private List<decimal> itemTotals;
public decimal calculateGrandTotal()
{
decimal subTotal =0m;
for(decimal itemTotal: itemTotals)
{
subTotal+=itemTotal;
}
//获取itemTotals的元素总和 subTotal get()
if (discounts.size()>0)
{
for(decimal discount: discounts)
{
subTotal-=discount;
}
}
//由subTotal减去discounts集合里的所有元素,subTotal get(discounts)
decimal tax=subTotal*0.065m;
subTotal +=tax;
//由subTotal计算出tax和subTotal的和,subTotal get(subTotal)
return subTotal;
}
}
重构:分解出三个方法,注意:对于方法内使用的参数如果是成员变量则无需作为方法参数传入而直接使用它。
class Receipt
{
private List<decimal> discounts;
private List<decimal> itemTotals;
//对于参数是成员变量,无需作为一个方法参数传入(get(List list)),直接使用即可(get()).
//获取ItemTotals集合的总和
public decimal getItemTotals()
{
decimal subTotal =0m;
/* for(decimal itemTotal: itemTotals)
{
subTotal+=itemTotal;
}
*/
subTotal+=getListAll(itemTotals);
return subTotal;
}
//获得集合的元素之和
public decimal getListAll(List<decimal> list)
{
decimal total=0;
for(decimal d:list)
{
total+=d;
}
return total;
}
//获得Discounts之和并与subTotal的差值
public decimal getDiscounts(decimal subTotal)
{
if(discounts.size()>0)
{
subTotal-=getListAll(discounts);
}
}
//获取最后的计算结果
public decimal getTax(decimal subTotal)
{
decimal tax=subTotal*0.065m;
subTotal +=tax;
return subTotal;
}
public decimal calculateGrandTotal()
{
decimal subTotal=getItemTotals();
subTotal=getDiscounts(subTotal);
subTotal=getTax(subTotal);
return subTotal;
}
}
5.策略类使用
策略模式(相当于IoC):使用该模式可以代替switch,if else语句的使用,从而达到解耦的目的,提高代码的可维护性。
IoC(控制反转):对象A依赖于对象B,当对象 A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办。
eg:ClientCode类对ShippingInfo对象有依赖,其中调用了State枚举类
//ClientCode类调用ShippingInfo对象的方法,该方法调用了枚举类
class ClientCode
{
public int calculateShipping()
{
//调用ShippingInfo对象
ShippingInfo info=new ShippingInfo();
//调用其方法,该方法调用枚举类
return info.calculateShippingAmount(State.NY);
}
}
enum State
{
NY,HK,TK;
}
class ShippingInfo
{
public int calculateShippingAmount(State state)
{
switch (state)
{
case NY:
getNYAmount();
case HK:
getHKAmount();
case TK:
getTKAmount();
default:
return 0;
}
}
public int getNYAmount()
{
return 10;
}
public int getHKAmount()
{
return 5;
}
public int getTKAmount()
{
return 3;
}
}
重构:
//将选择结构的选择方式,变为选择集合中的某个元素
//即 State-调用->相应的Method变为Map.get(Sate)->Method,;根据key取value(->Method)
//Strategy抽象类作为value,State枚举作为key,StrategyFactory工厂类,作为封装集合,存储元素,取出元素
class ClientCode
{
public int calculateShipping()
{
ShippingInfo info=new ShippingInfo();//这里建议使用依赖注入实现: @inject Shipping info;//前提是有注入框架
return info.calculateShippingAmount(State.HK);
}
}
enum State
{
NY,HK,TK;
}
//策略类:将调用的3个方法封装成3个策略类
interface Strategy
{
int getAmount();
}
class NYAmount implements Strategy
{
@Override
public int getAmount() {
// TODO Auto-generated method stub
return 10;
}
}
class HKAmount implements Strategy
{
@Override
public int getAmount() {
// TODO Auto-generated method stub
return 5;
}
}
class TKAmount implements Strategy
{
@Override
public int getAmount() {
// TODO Auto-generated method stub
return 3;
}
}
//StrategyFactory工厂类:单态设计模式,存储/取出对象
class StrategyFactory
{
private static StrategyFactory factory=new StrategyFactory();
private static Hashtable<State, Strategy> ht=new Hashtable<>();
static {
ht.put(State.NY, new NYAmount());
ht.put(State.HK, new HKAmount());
ht.put(State.TK, new TKAmount());
}
private StrategyFactory() {
// TODO Auto-generated constructor stub
}
public static StrategyFactory getInstance()
{
return factory;
}
public Strategy getStrategy(State key)
{
return ht.get(key);
}
}
class ShippingInfo
{
public int calculateShippingAmount(State state)
{
StrategyFactory factory=StrategyFactory.getInstance();
return factory.getStrategy(state).getAmount();
}
}