针对Android开发的4种优化重载小技巧

点击上方蓝字关注公众号

码个蛋第317次推文

作者:AWeiLoveAndroid

博客:https://www.jianshu.com/p/b74107b6464d

在平时Android开发中,可能会出现某个类有很多个重载方法。

这个问题很多人在维护项目的时候可能会经常遇到,比如需求变更,刚开始只有一个构造方法,传入一个参数的。如下所示:

public class Demo{

   private int a;

   public Demo(int a){
       this.a=a; 
       //do something...
   }
}


后来需求变更,传入两个参数比较符合业务逻辑,如下图所示:

public class Demo{
   
   private int a;
   private int b;

   public Demo(int a){
       //do something...
       this(a,0); 
   }

   public Demo(int a,int b){
       this.a=a; 
       this.b=b; 
       //do something...
   }
}

再到后来随着业务逻辑的扩展,可能会有3个构造方法。可能每个构造方法里面的逻辑也有所不一样。如下所示:

public class Demo{
   
   private int a;
   private int b;
   private int c;

   public Demo(int a){
       //do something...
       this(a,0); 
   }

   public Demo(int a,int b){
       //do something...
       this(a,b,0); 
   }

   public Demo(int a,int b,int c){
       this.a=a; 
       this.b=b; 
       this.c=c;   
          //do something...
   }

}

甚至有4个构造方法的:

public class Demo{
   
   private int a;
   private int b;
   private int c;
   private int d;

   public Demo(int a){
       //do something...
       this(a,0); 
   }

   public Demo(int a,int b){
       //do something...
       this(a,b,0); 
   }

   public Demo(int a,int b,int c){
       //do something...
       this(a,b,c,0);  
   }

   public Demo(int a,int b,int c,int d){ 
       this.a=a; 
       this.b=b; 
       this.c=c;  
       this.d=d; 
                  //do something...
   }

}

随着业务的发展,方法越来越多,越来越不好维护,重载方法之间的逻辑也不大相同。那么遇到这种问题应该怎么最好的优化呢?

1

 @Deprecated 注解标记方法过时

 

建议在哪个版本中使用哪个方法,这样也起一个标记的作用。

【优点】暂时解决了方法维护的问题,开发人员不再为过时方法维护了,而且旧版本也可以使用相应方法,对老版本兼容性比较好。
【缺点】所有的方法都在,还是有那么多冗余代码,还是没从根源上解决问题。

示例如下:

public class Demo{
   
   private int a;
   private int b;
   private int c;
   private int d;

   public Demo(int a){
       //do something...
       this(a,0); 
   }

   //比如在app的v1.0.0版本中在这个构造方法中标记为过时,后续版本中不使用该方法
   @Deprecated
   {@link Demo(int, int, int)}
   public Demo(int a,int b){
       //do something...
       this(a,b,0); 
   }

   public Demo(int a,int b,int c){
       //do something...
       this(a,b,c,0);  
  }

   public Demo(int a,int b,int c,int d){ 
       this.a=a; 
       this.b=b; 
       this.c=c;  
       this.d=d; 
       //do something...
   }

}

2

把参数实例化成一个实体类

 

构造里面引入这个实体类,想要哪些属性,通过getter和setter来访问成员变量。

【优点】解决了代码冗余问题。
【缺点】针对不同版本设置的代码不一样,代码量还是很大的。

示例代码如下:

//封装一个实体类
public class DataBean{

   private int dataA;
   private int dataB;
   private int dataC;
   private int dataD;

   public int getDataA() {
       return dataA;
   }

   public void setDataA(int dataA) {
       this.dataA = dataA;
   }

   public int getDataB() {
       return dataB;
   }

   public void setDataB(int dataB) {
       this.dataB = dataB;
   }

   public int getDataC() {
       return dataC;
   }

   public void setDataC(int dataC) {
       this.dataC = dataC;
   }

   public int getDataD() {
       return dataD;
   }

   public void setDataD(int dataD) {
       this.dataD = dataD;
   }

   //篇幅有限,toString,equals和hasCode方法省去不写了
}

然后我加了一个接口,处理版本号码的问题,所有的版本号码都可以写在这个接口里面,都是int类型的,实质相当于枚举,因为枚举比较耗性能,所以就用接口替代了。(为什么写接口,写接口方便扩展,性能好。)

/**
* 处理版本号的接口
*/
public interface IVersionCode {
   public int VERSION_ONE = 1;
   public int VERSION_TWO = 2;
   public int VERSION_THREE = 3;
   public int VERSION_FOUR = 4;
}

然后原代码里面只需要传入这个DataBean实体类就可以了,同时实现了IVersionCode接口,可以直接使用里面的常量。

再看看原来那个类的变化:

public class Demo implements IVersionCode{

   private DataBean dataBean;
   //通过一个LinkedList有序列表去保存版本号
   private List<Integer> mLinkedList = new LinkedList<>();

   public Demo(DataBean bean){
       this.dataBean = bean;
   }

   /**
    * 设置版本信息
    * 传入一个版本号,根据对应的版本号设置对应的方法
    *
    */
   public void setVersion(int versionName){
       switch(versionName){
           //假如是版本VERSION_ONE,调用的是一个参数
           case VERSION_ONE:
               //避免重复添加
               if(!mLinkedList.contains(VERSION_ONE)){
                   mLinkedList.add(VERSION_ONE);
               }
               dataBean.setDataA(1);
               //do something...
               break;
           case VERSION_TWO:
               if(!mLinkedList.contains(VERSION_TWO)){
                   mLinkedList.add(VERSION_TWO);
               }
               dataBean.setDataA(1);
               dataBean.setDataB(2);
               //do something...
               break;
           case VERSION_THREE:
               if(!mLinkedList.contains(VERSION_THREE)){
                   mLinkedList.add(VERSION_THREE);
               }
               dataBean.setDataA(1);
               dataBean.setDataB(2);
               dataBean.setDataC(3);
               //do something...
               break;
           case VERSION_FOUR:
               if(!mLinkedList.contains(VERSION_FOUR)){
                   mLinkedList.add(VERSION_FOUR);
               }
               dataBean.setDataA(1);
               dataBean.setDataB(2);
               dataBean.setDataC(3);
               dataBean.setDataD(4);
               //do something...
               break;
           default:
               break;
       }
   }

   /**
    * 根据获取的版本信息得到实体类对象
    * 调用get方法就可以拿到实体类里面的具体方法
    * @return
    */
   public DataBean getVersion(int versionName){
       for(int i =0; i<mLinkedList.size(); i++){
           if(mLinkedList.get(i) == VERSION_ONE){
               dataBean.getDataA();
           }else if(mLinkedList.get(i) == VERSION_TWO){
               dataBean.getDataA();
               dataBean.getDataB();
           }else if(mLinkedList.get(i) == VERSION_THREE){
               dataBean.getDataA();
               dataBean.getDataB();
               dataBean.getDataC();
           }else if(mLinkedList.get(i) == VERSION_FOUR){
               dataBean.getDataA();
               dataBean.getDataB();
               dataBean.getDataC();
               dataBean.getDataD();
           }
       }
      return dataBean;
   }
}

那么有没有一种更好的解决方案呢?我觉得目前能够想出来的解决方案就是下面这种了

3

使用建筑者模式

 

把Demo这个类的构建对象的操作转移到内部类里面去执行,对外隐藏对象创建的细节。

【优点】这种对象的构建方式不但解决了代码可读性的问题,并大幅减少了构造参数,构建过程保证了一定的一致性。
【缺点】建造者模式的产品的组件基本相同,如果产品的差异性较大,建造者模式就不适用了。

示例代码如下:

public class Demo{
   
   private int dataA;
   private int dataB;
   private int dataC;
   private int dataD;

   private Demo(Builder builder) {
       this.dataA = builder.dataA; 
       this.dataB = builder.dataB; 
       this.dataC = builder.dataC;  
       this.dataD = builder.dataD; 
   }

   public void setA(int a){
       this.dataA = a;
   }

   public void setB(int b){
       this.dataB = b;
   }

   public void setC(int c){
       this.dataC = c;
   }

   public void setD(int d){
       this.dataD = d;
   }

   public void getA(int a){
       return dataA;
   }

   public void getB(int b){
       return dataB;
   }

   public void getC(int c){
       return dataC;
   }

   public void getD(int d){
       return dataD;
   }


   public static class Builder {  

       private int dataA;
       private int dataB;
       private int dataC;
       private int dataD;

       public Demo build() {  
           return new Demo(this);  
       } 

       public Builder getDataA(int a) {  
           this.dataA = a;  
           return this;  
       } 

       public Builder getDataB(int b) {  
           this.dataB = b;  
           return this;  
       } 

       public Builder getDataC(int c) {  
           this.dataC = c;  
           return this;  
       } 

       public Builder getDataD(int d) {  
           this.dataD = d;  
           return this;  
       } 

   }

}

4

使用接口回调来处理

 

实体类稍微改了一下:

public class DataBean{

   public static final String TAG = DataBean.class.getSimpleName();

   private int dataA;
   private int dataB;
   private int dataC;
   private int dataD;

   /**
    *  是否已经设置了A属性,解决不同版本何止不同的参数问题
    */
   private boolean isDataASetted;
   /**
    *  是否已经设置了B属性,解决不同版本何止不同的参数问题
    */
   private boolean isDataBSetted;
   /**
    *  是否已经设置了C属性,解决不同版本何止不同的参数问题
    */
   private boolean isDataCSetted;
   /**
    *  是否已经设置了D属性,解决不同版本何止不同的参数问题
    */
   private boolean isDataDSetted;


   public int getDataA() {
       Log.d(TAG, "getDataA: " + dataA);
       return dataA;
   }

   public void setDataA(int dataA) {
       this.dataA = dataA;
   }

   public int getDataB() {
       Log.d(TAG, "getDataB: " + dataB);
       return dataB;
   }

   public void setDataB(int dataB) {
       this.dataB = dataB;
   }

   public int getDataC() {
       Log.d(TAG, "getDataC: " + dataC);
       return dataC;
   }

   public void setDataC(int dataC) {
       this.dataC = dataC;
   }

   public int getDataD() {
       Log.d(TAG, "getDataD: " + dataD);
       return dataD;
   }

   public void setDataD(int dataD) {
       this.dataD = dataD;
   }

   public boolean isDataASetted() {
       return isDataASetted;
   }

   public void setDataASetted(boolean dataASetted) {
       isDataASetted = dataASetted;
   }

   public boolean isDataBSetted() {
       return isDataBSetted;
   }

   public void setDataBSetted(boolean dataBSetted) {
       isDataBSetted = dataBSetted;
   }

   public boolean isDataCSetted() {
       return isDataCSetted;
   }

   public void setDataCSetted(boolean dataCSetted) {
       isDataCSetted = dataCSetted;
   }

   public boolean isDataDSetted() {
       return isDataDSetted;
   }

   public void setDataDSetted(boolean dataDSetted) {
       isDataDSetted = dataDSetted;
   }

   @Override
   public String toString() {
       return "DataBean{" +
               "dataA=" + dataA +
               ", dataB=" + dataB +
               ", dataC=" + dataC +
               ", dataD=" + dataD +
               ", isDataASetted=" + isDataASetted +
               ", isDataBSetted=" + isDataBSetted +
               ", isDataCSetted=" + isDataCSetted +
               ", isDataDSetted=" + isDataDSetted +
               '}';
   }

   @Override
   public boolean equals(Object o) {
       if (this == o)
           return true;
       if (o == null || getClass() != o.getClass())
           return false;

       DataBean dataBean = (DataBean) o;

       if (dataA != dataBean.dataA)
           return false;
       if (dataB != dataBean.dataB)
           return false;
       if (dataC != dataBean.dataC)
           return false;
       if (dataD != dataBean.dataD)
           return false;
       if (isDataASetted != dataBean.isDataASetted)
           return false;
       if (isDataBSetted != dataBean.isDataBSetted)
           return false;
       if (isDataCSetted != dataBean.isDataCSetted)
           return false;
       return isDataDSetted == dataBean.isDataDSetted;
   }

   @Override
   public int hashCode() {
       int result = dataA;
       result = 31 * result + dataB;
       result = 31 * result + dataC;
       result = 31 * result + dataD;
       result = 31 * result + (isDataASetted ? 1 : 0);
       result = 31 * result + (isDataBSetted ? 1 : 0);
       result = 31 * result + (isDataCSetted ? 1 : 0);
       result = 31 * result + (isDataDSetted ? 1 : 0);
       return result;
   }

}

原来的那个类改造如下:

public class Demo implements IVersionCode{

   private DataBean dataBean;
   private OnVersionChoosedListener mOnVersionChoosedListener;

   public Demo(DataBean bean){
       this.dataBean = bean;
   }


   /**
    * 设置版本名
    */
   public void setVersion(int versionName){
       switch(versionName){
           case VERSION_ONE:
               dataBean.setDataA(1);
               dataBean.setDataASetted(true);
               dataBean.setDataBSetted(false);
               dataBean.setDataCSetted(false);
               dataBean.setDataDSetted(false);
               mOnVersionChoosedListener.setVersion(versionName,dataBean);
               //do something...
               break;
           case VERSION_TWO:
               dataBean.setDataA(1);
               dataBean.setDataB(2);
               //表示在这个版本只有A B这两个方法是有效的
               dataBean.setDataASetted(true);
               dataBean.setDataBSetted(true);
               dataBean.setDataCSetted(false);
               dataBean.setDataDSetted(false);
               mOnVersionChoosedListener.setVersion(versionName,dataBean);
               //do something...
               break;
           case VERSION_THREE:
               dataBean.setDataA(1);
               dataBean.setDataB(2);
               dataBean.setDataC(3);
               dataBean.setDataASetted(true);
               dataBean.setDataBSetted(true);
               dataBean.setDataCSetted(true);
               dataBean.setDataDSetted(false);
               mOnVersionChoosedListener.setVersion(versionName,dataBean);
               //do something...
               break;
           case VERSION_FOUR:
               dataBean.setDataA(1);
               dataBean.setDataB(2);
               dataBean.setDataC(3);
               dataBean.setDataD(4);
               dataBean.setDataASetted(true);
               dataBean.setDataBSetted(true);
               dataBean.setDataCSetted(true);
               dataBean.setDataDSetted(true);
               mOnVersionChoosedListener.setVersion(versionName,dataBean);
               //do something...
               break;
           default:
               break;
       }

   }

   public DataBean getVersion(){
       if(dataBean.isDataASetted()){
           dataBean.getDataA();
       }
       if(dataBean.isDataBSetted()){
           dataBean.getDataB();
       }
       if(dataBean.isDataCSetted()){
           dataBean.getDataC();
       }
       if(dataBean.isDataDSetted()){
           dataBean.getDataD();
       }
       return dataBean;
   }

   public int getVersionName(){
       return mOnVersionChoosedListener.getVersionName();
   }




   interface OnVersionChoosedListener{
       /**
        * 设置版本
        * @param version
        * @param dataBean
        */
       void setVersion(int version, DataBean dataBean);

       /**
        * 获取版本号
        * @return
        */
       int getVersionName();

       /**
        * 获取对应的实体类对象 方便下一步的操作
        * @return
        */
       DataBean getVersion();

   }

   public void setOnVersionChoosedListener(@NonNull OnVersionChoosedListener onVersionChoosedListener) {
       mOnVersionChoosedListener = onVersionChoosedListener;
   }
}

如果你还有更好的解决方式,欢迎提出疑问,留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值