重构方法学习—对函数进行重构

1. Extract Method(提炼函数)

  • 含义:
    • 将一部分代码提炼成一个小的方法,然后替换原有逻辑的地方
  • 三种情况
    • 无局部变量
    • 有局部变量
    • 对局部变量再赋值
      • 局部变量只在提炼代码赋值:直接提炼成方法就可以
      • 局部变量之外也使用了此变量
        • 局部变量在提炼方法后面没有使用,那么直接在提炼的目标方法中修改就可以了
        • 局部变量在提炼方法后面仍然使用,那么通过返回结果返回该变量改变后的值

2. Inline Method(内联函数)

  • 含义:
    • 在函数调用的地方,使用函数体来替换函数的调用,然后删除函数
  • 适用情况
    • 函数定义不合理
    • 函数和调用它的函数意义相同

3. Inline Temp(内联临时变量)

  • 含义
    • 将所有对该变量的引用动作,替换为对它赋值的那个表达式自身
  • 解释
    • 存在问题的代码,可以看出basePrice获取值之后,只是用来判断语句,简单操作,没必要赋值之后再进行操作
    double price  = anOrder.basePrice();
    return (price > 1000)
    
    • 优化
    return (anOrder.basePrice()>1000)
    
  • 适用场景
    • 某个变量被赋值为某个函数执行之后的返回值,而且,这个临时变量不会对其他流程进行影响。可以放在哪里,但是如果影响了抽象方法或者其他重构的方法,为何会影响呢,因为抽象是对方法体抽象,现在方法体内部又包含了临时变量,是否会发生影响,而且不必要的依赖是不需要的,所以必须内联临时变量

4. Replace Temp with Query(以查询取代临时变量)

  • 含义
    • 将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数的调用,此后,新函数就可被其他函数使用
  • 原因
    • 临时变量,本来就是暂时的。只能在函数中使用
    • 因为临时变量会增加方法的长度,所以,如果你需要临时变量,那么无疑你的函数会变得很长
    • 如果很多方法都需要此临时变量,那么变成一个方法,可以很好地重用
  • 适用场景
    • 临时变量被赋值过一次
    • 赋值给临时变量的表达式不受其他条件影响

5. Introduce Explaining Variable(引入解释性变量)

  • 含义
    • 将该复杂表达式(或者表达式一部分)的结果放到一个临时变量,以此变量名称来解释表达式用途。
  • 原因
    • 当看代码,很难看出目的是什么的时候,就应该为表达式创建一个临时变量,来解释此段表达式的含义

6. Remove Assignments to Parameters(移除对参数的赋值)

  • 含义:
    • 以一个临时变量取代该参数的位置
  • 原因
    • 如果是值传递的话,不会对之前的数据造成影响
    • 如果是引用传递的话,如果直接修改了参数内部的属性,那么和入参引用相同对象的。实参引用的相同对象的内部属性也会发生改变。这个是很隐藏的,如果不注意会出现很大的问题。所以如果不是对引用变量进行修改的话,使用入参新建一个变量来进行操作,防止实参发生不必要的改变,看一波下面的代码想一下结果
    public class RemoveAssignments {
    
        public static void main(String[] args) {
            Date d1 = new Date("1 Apr 98");
            System.out.println("d1 before nextDay: "+d1);
            nextDateUpdate(d1);
            System.out.println("d1 after nextDay: "+d1);
    
            Date d2 = new Date("1 Apr 98");
            nextDateReplace(d2);
            System.out.println("d2 after nextDay : "+d2);
        }
    
        private static void nextDateReplace(Date arg) {
    
            //只要是new了一个对象,那么就是重新指向了其他对象,
            //如果是两个引用都是同一个对象,一个修改了对象的内部,那么两个引用都会改变
            //如果是修改了一个引用所引用的对象,那么另一个引用还是一直的对象,不会受到影响
            arg = new Date(arg.getYear(),arg.getMonth(),arg.getDate()+1);
            System.out.println("arg in nextDay: "+ arg);
        }
    
        private static void nextDateUpdate(Date arg) {
            arg.setDate(arg.getDate()+1);
            System.out.println("arg in nextDay: "+arg);
        }
    }
    

7. Replace Method with Method Object(以函数对象取代函数)

  • 含义

    • 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后你可以在同一个对象中将这个大型函数分解为多个小型函数。
  • 原因

    • 局部变量的存在会增加函数分解难度。如果一个函数之中局部变量泛滥成灾,那么像分解这个函数是非常困难的。然后就使用了一个函数对象,将局部变量变成属性,然后将这个函数使用属性来拆分成小的函数
  • 看一个案例

    • 源对象,拆分前
    public class Account {
    
        //想象这个是一个很长的方法,且局部变量很多,导致的结果,很难抽出方法
        //解决方法,使用函数对象来拆分此方法
        public int gamma(int inputValue,int quantity,int yearToDate){
            int importantValue1 = (inputValue * quantity) + delta();
            int importantValue2 = (inputValue * quantity) + 200;
            if((yearToDate -importantValue1)>100){
                importantValue2-=20;
            }
            int importantValue3 = importantValue2 * 7;
            return importantValue3 - 2 * importantValue1;
        }
    
        public int delta(){
            return 100;
        }
    }
    
    • 拆分成函数对象之后,拆分出一个类,使用了函数名称的类,gamma
    • Account类(拆分后)
    public class Account {
    
        public int gamma(int inputValue,int quantity,int yearToDate){
            return new Gamma(this,inputValue,quantity,yearToDate).compute();
        }
    
        public int delta(){
            return 100;
        }
    }
    
    • 函数抽象类
    public class Gamma {
    
        //将之前的对象,传递进来,为何,因为需要使用源对象中的方法,如果是属性可以以构造器入参的方式传入
        private final Account _source;
    
        //本来gamma方法的三个入参,变成了属性
        private int inputValue;
        private int quantity;
        private int yearToDate;
    
        //gamma方法中的局部变量,修改成属性,这个可以在拆分后的方法中使用
        //此类为函数对象,实质上只是为了拆分长函数而产生的,不能存在其他函数的拆分
        //否则,属性会很多,不易维护
        private int importantValue1;
        private int importantValue2;
        private int importantValue3;
    
        //源对象和入参以构造器的方式传入
        public Gamma(Account _source, int inputVal, int quantity, int yearToDate) {
            this._source = _source;
            this.inputValue = inputVal;
            this.quantity = quantity;
            this.yearToDate = yearToDate;
        }
    
    
        //编写需要拆分的方法
        int compute(){
    
            //这个就是为什么要传入源函数
            importantValue1 = (inputValue * quantity) + _source.delta();
            importantValue2 = (inputValue * quantity) + 200;
    
            //此处仅对其进行拆分,之前由于引用的局部变量太多,不易拆分
            //如果是函数对象的话,属性在此类中都是可以访问到的,所以不需要传入
            //属性表示的入参,可以极大的简化拆分的方法,同时对于方法内修改局部变量
            //因为此局部变量现在也成了属性,所以不用返回来进行重新赋值,如果是抽象方法的话
            //此处应该写下面的一行代码,很明显,抽象对象不仅简化了入参,而且也简化了局部变量的修改
            //importantValue2 = importantThing();
    
    
    //        if((yearToDate -importantValue1)>100){
    //            importantValue2-=20;
    //        }
    
            //函数抽象之后的赋值,不需要重新给importantValue2赋值,因为现在不是局部临时变量
            //而是类的属性,类中共享
            importantThing();
    
            int importantValue3 = importantValue2 * 7;
            return importantValue3 - 2 * importantValue1;
        }
    
        public void importantThing(){
            if((yearToDate -importantValue1)>100){
                importantValue2-=20;
            }
        }
    }
    

8. 替换算法

  • 含义:
    • 将函数本体替换为另一个算法
  • 原因
    • 如果发现一个函数的实现可以使用更好地一种算法,那么就应该以比较清晰的方式取代复杂的方式。嗯。。。。。。,感觉都是这么干的
  • 总之,使用好的实现,如果发现了好的实现,新旧对比,然后择优实现即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 重构printf函数的目的是为了实现串口打印输出功能。在重定义printf函数之前,需要在代码中添加头文件和函数声明。首先,添加头文件"stdarg.h"并在main函数下方添加printf函数的声明。然后,在代码中添加宏定义,根据使用的编译器选择相应的宏定义。如果使用的是GCC编译器,则定义宏__io_putchar(int ch),否则定义宏fputc(int ch, FILE *f)。这些宏定义的作用是告诉编译器使用哪个函数来实现输出功能。最后,实现重构后的printf函数,通过HAL_UART_Transmit函数将字符发送到串口。这样就完成了printf函数重构。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [STM32—printf函数重定义](https://blog.csdn.net/u014470361/article/details/79203273)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [STM32 重构printf函数](https://blog.csdn.net/qq_20999867/article/details/100076134)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值