《重构-改善既有代码的设计》- 重新组织函数

所谓的重构就是在不改变代码外部行为(功能)的情况下对代码进行内部修改以实现代码可读性、可维护性、可复用性以及可扩展性的大幅度增加,便于后续进行扩展和维护(直观提高代码可读性,利于定位Bug并加以修复)。

避免出现 “too-long" 方法,要求方法表现的逻辑简洁明了(concise and easy to understand)。

🍎【Extract Method】- 提炼方法

将代码放入一个独立方法中,并让方法的名称具有自我描述性

特点:

  1. 功能模块化
  2. 模块集成化
  3. 局部变量局部化
  4. 初始变量分离化

处理对象:

  1. 过长方法
  2. 方法包含的代码逻辑复杂混乱,直观性差。

实现目标:
降低方法粒度,提高方法复用性,让高层函数读起来像是(just like)读注释一样。

方法粒度小便于后续的复写、复用和扩展

class Order {
private double price;
public Order(double price){
this.price = price;
}
double getAmount(){
return this.price;
}
}
public class Sample01 {
private Vector<Order> _orders;
private String _name;
public Sample01(String name){
this._name = name;
}
//【高层函数】遵守"单一指责型"这个原则,实现模块(方法)功能独立
void printOwing(){
printBanner(); // print banner
double outstanding = getOutstanding(); // calculate outstanding
printDetails(_name,outstanding); // print details
}
// calculate outstanding 【局部变量局部化】
private double getOutstanding() {
Enumeration e = _orders.elements();
double result = 0.0;
while(e.hasMoreElements()){
Order order = (Order)e.nextElement();
result += order.getAmount();
}
return result;
}
// print details
private void printDetails(String username, Double outstanding) {
System.out.println("username: " + username);
System.out.println("amount: " + outstanding);
}
// print banner
private void printBanner() {
System.out.println("*************************");
System.out.println("***** Customer Owes *****");
System.out.println("*************************");
}
}
/**
* the characteristic of Extract Method
* 1. 局部变量局部化
* 2. 初始变量分离化
* 3. 功能模块化
* 4. 模块集成化
* */

🍎【Inline Method】- 内联方法

在函数调用点插入函数本体,然后移除函数

处理对象: 代码之间太多的间接层(间接层有价值但不是所有的间接层都有价值)

🍎【Inline Temp】- 内联临时变量

将所有对该变量的引用动作,替换为对它赋值的表达式本身

处理对象:减少临时变量的出现,只用通过内联表达式来达到临时变量的作用(内联临时变量要用于所替代临时变量只会被使用一次的情况下)

🍎【Replace Temp With Query】- 以查询取代临时变量

将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数调用
特点:

  1. 模块功能化
  2. 功能集成化

处理对象: 减少长函数的出现

确保提炼出来的函数无任何副作用,该函数并不修改任何对象内容。
运用此方法可能会存在性能方面的考虑,但如果性能真的出现问题可以在优化阶段解决。代码组织良好更有助于发现有效的优化方案

🍎【Introduce Explaining Variable】- 引入解释型变量

将该复杂表达式(或其中一部分)的结果放进一个临时比那辆,以此变量名称来解释表达式用途

处理好处: 通过自我描述性的变量代替冗杂、逻辑不清的表达式以提高代码可读性(concise and easy to understand)

public class Sample05 {
private double _quantity;
private double _itemPrice;
// *************** initial version 1.0.0 ***************
double calculatePrice01(){
// price is base_price - quantity_discount + shipping
return _quantity * _itemPrice -
Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
Math.min(_quantity * _itemPrice * 0.1, 100.0);
}
// *************** 【Introduce Explaining Variables】initial version 1.0.1 ***************
double calculatePrice02(){
// price is base_price - quantity_discount + shipping
final double basePrice = _quantity * _itemPrice;
return basePrice -
Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
Math.min(basePrice * 0.1, 100.0);
}
// *************** 【Introduce Explaining Variables】initial version 1.0.2 ***************
double calculatePrice03(){
// price is base price - quantity discount + shipping
final double basePrice = _quantity * _itemPrice;
final double quantityDiscount = Math.max(0, _quantity - 500) * _itemPrice * 0.05;
final double shipping = Math.min(basePrice * 0.1, 100.0);
return basePrice - quantityDiscount + shipping;
}
// *************** 【Extract Method】initial version 1.0.3 ***************
double calculatePrice04(){
return basePrice() - quantityDiscount() + shipping();
}
private double basePrice(){
return _quantity * _itemPrice;
}
private double quantityDiscount(){
return Math.max(0, _quantity - 500) * _itemPrice * 0.05;
}
private double shipping(){
return Math.min(basePrice() * 0.1, 100.0);
}
// Concise and easy to understand
}

🍎【Remove Assignments to Parameters】- 移除对参数的赋值

以一个临时变量取代该参数的位置

public class Sample07 {
// ****************【Remove Assignments To Parameters】version 1.0.0 ****************
int discount01(int inputVal, int quantity, int yearToDate){
if(inputVal > 50){
inputVal -= 2;
}
if(quantity > 100){
inputVal -= 1;
}
if(yearToDate > 10000){
inputVal -= 4;
}
return inputVal;
}
// ****************【Remove Assignments To Parameters】version 1.0.1 ****************
int discount02(int inputVal, int quantity, int yearToDate){
int result = inputVal;
if(inputVal > 50){
result -= 2;
}
if(quantity > 100){
result -= 1;
}
if(yearToDate > 10000){
result -= 4;
}
return result;
}
// ****************【Remove Assignments To Parameters】version 1.0.2 ****************
int discount03(final int inputVal, final int quantity, final int yearToDate){ // final: 1. 保证变量一致性 2. 防止出现参数再次赋值
int result = inputVal;
if(inputVal > 50){
result -= 2;
}
if(quantity > 100){
result -= 1;
}
if(yearToDate > 10000){
result -= 4;
}
return result;
}
// To implement compulsory no-assignment to parameter with the "final" keyword.(the "final" better use in too long method)
}

🍎【Split Temporary Variable】- 分解临时变量

针对每次赋值,创建一个独立、对应的临时变量(临时变量的唯一化和遵守单一职责的原则)

🍎【Replace Method With Method Object】- 以函数对象取代函数

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

处理对象: 无法拆解的方法
处理好处:将相对独立的代码从大型函数中提炼处理啊,就可以大大提高代码的可读性。

class Account{
private int inputVal;
private int quantity;
private int yearToDate;
// traditional Method
int gamma01(int inputVal, int quantity, int yearToDate){
int importantValue1 = (inputVal * quantity) + delta();
int importantValue2 = (inputVal * yearToDate) + 100;
if((yearToDate - importantValue1) > 100){
importantValue2 -= 20;
}
int importantValue3 = importantValue2 * 7;
// and so on
return importantValue3 - 2 * importantValue1;
}
int gamma02(int inputVal, int quantity, int yearToDate){ 【⭐️Nice Shot】
return new Gamma(this,inputVal,quantity,yearToDate).compute();
}
int delta(){
return 1;
}
}
// Method Object
class Gamma{
private final Account _account; // The _account field must be used anywhere in a function that calls the Account class
private int inputVal;
private int quantity;
private int yearToDate;
// 【extract method】
// private int importantValue1;
// private int importantValue2;
// private int importantValue3;
Gamma(Account source, int inputValArg, int quantityArg, int yearToDateArg){
this._account = source;
this.inputVal = inputValArg;
this.quantity = quantityArg;
this.yearToDate = yearToDateArg;
}
// refactoring method
int compute(){
if((yearToDate - importantValue1()) > 100){
return getImportantValue3(importantValue2() - 20) - 2 * importantValue1();
}
return getImportantValue3(importantValue2()) - 2 * importantValue1();
}
int importantValue1(){
return (inputVal * quantity) + _account.delta();
}
int importantValue2(){
return (inputVal * yearToDate) + 100;
}
int getImportantValue3(int val){
return val * 7;
}
}

🍎【Substitute Algorithm】- 替换算法

把某个算法替换为另一个更清晰的算法

"重构"充分发挥Divide and Conquer的思想,将复杂的东西分解为小块。

posted @   Felix_Openmind  阅读(153)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}
点击右上角即可分享
微信分享提示