美文网首页@IT·互联网程序员Android技术知识
针对Android中类的重载方法很多时的几种优化解决方案

针对Android中类的重载方法很多时的几种优化解决方案

作者: AWeiLoveAndroid | 来源:发表于2018-03-20 23:19 被阅读1550次

    在平时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...
        }
    
    }
    

    随着业务的发展,方法越来越多,越来越不好维护,重载方法之间的逻辑也不大相同。那么遇到这种问题应该怎么最好的优化呢?我这里给出了 以下几种方案 供大家选择:

    一、可以模仿Android源码,使用 @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...
        }
    
    }
    
    二、根据面向对象的思想,把参数实例化成一个实体类,然后构造里面引入这个实体类,想要哪些属性,通过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;
        }
    }
    

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

    三、使用建筑者模式,把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;  
            } 
    
        }
    
    }
    
    四、使用接口回调来处理

    实体类稍微改了一下:

    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;
        }
    }
    
    五、使用观察者模式处理

    。。。待完善。。。


    基本就这些了,如果你还有更好的解决方式,欢迎提出疑问,留言或者私信我都可以。

    喜欢的话就打赏点个赞 吧!

    相关文章

      网友评论

        本文标题:针对Android中类的重载方法很多时的几种优化解决方案

        本文链接:https://www.haomeiwen.com/subject/dsyiqftx.html