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

简介: 在平时Android开发中,可能会出现某个类有很多个重载方法。这个问题很多人在维护项目的时候可能会经常遇到,比如需求变更,刚开始只有一个构造方法,传入一个参数的。

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

。。。待完善。。。


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

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

相关文章
|
7天前
|
存储 消息中间件 人工智能
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
55 10
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
|
4月前
|
Android开发 开发者
Android自定义view之利用drawArc方法实现动态效果
本文介绍了如何通过Android自定义View实现动态效果,重点使用`drawArc`方法完成圆弧动画。首先通过`onSizeChanged`进行测量,初始化画笔属性,设置圆弧相关参数。核心思路是不断改变圆弧扫过角度`sweepAngle`,并调用`invalidate()`刷新View以实现动态旋转效果。最后附上完整代码与效果图,帮助开发者快速理解并实践这一动画实现方式。
133 0
|
2月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
160 11
|
6月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
1273 77
|
4月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
168 1
|
6月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
11月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
378 15
Android 系统缓存扫描与清理方法分析
|
10月前
|
开发框架 前端开发 Android开发
探索安卓和iOS应用开发中的跨平台解决方案
【10月更文挑战第42天】在移动应用开发的广阔天地中,安卓和iOS系统如同两座巍峨的山峰,分别占据着半壁江山。开发者们在这两座山峰之间穿梭,努力寻找一种既能节省资源又能提高效率的跨平台开发方案。本文将带你走进跨平台开发的世界,探讨各种解决方案的优势与局限,并分享一些实用的代码示例,助你在应用开发的道路上更加游刃有余。
|
11月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
182 4
|
11月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
242 1

热门文章

最新文章