Replace Temp With Query(以查询取代临时变量)

本文介绍了一种重构技巧,即将仅被赋值一次的临时变量转换为查询方法,以提高代码的可读性和可维护性。通过示例展示了如何逐步实现此重构过程。

double basePrice = _quantity * _itemPrice;
if(basePrice > 1000)
   return basePrice * 0.95;
else
   return basePrice * 0.98;

 

==>

 

if(basePrice() > 1000)
   return basePrice() * 0.95;
else
   return basePrice() * 0.98;

double basePrice() {
   return _quantity * _itemPrice;
}

动机

临时变量的问题在于:它们是暂时的,而且只能在所属函数内使用.由于临时变量只有在所属函数内才可见,所以它们会驱使你写出更长的函数,因为只有这样你才能访问到想要访问的临时变量.如果把临时变量替换为一个查询式(query method),那么同一个class中的所有函数都将可以获得这份信息.这将带给你极大帮助,使你能够为这个class编写更清晰的代码.

Replace Temp with Query(120)往往是你运用Extract Method(110)之前必不可少的一个步骤.局部变量会使代码难以被提炼,所以你应该尽可能把它们替换为查询式.

这个重构手法较为直率的情况就是:临时变量只被赋值一次,或者赋值给临时变量的表达式不受其他条件影响.其他情况比较棘手,但也有可能发生.你可能需要先运用Split Temporary Variable(128)或Separate Query from Modifier(279)使情况变得简单一些,然后再替换临时变量.如果你想替换的临时变量是用来收集结果的(例如循环中的累加值),你就需要将某些程序逻辑(例如循环)拷贝到查询式(query method)去.

作法:

1. 找出只被赋值一次的临时变量

如果某个临时变量被赋值超过一次,考虑使用Split Temporay Variable(128)将它分割成多个变量.

2. 将该临时变量声明为final.

3. 编译.这可确保该临时变量的确只被赋值一次.

4. 将[对临时变量赋值]之语句的等号右侧部分提炼到一个独立函数中

    首先将函数声明为private.日后你可能会发现有更多class需要使用它,彼时你可轻易放松对它的保护.

    确保提炼出来的函数无任何连带影响(副作用),也就是说该函数并不修改任何对象内容.如果它有连带影响,就对它进行Separate Query from Modifier(279).

5 编译,测试

6 在该临时变量身上实施Inline Temp(119).


double getPrice() {
   int basePrice = _quantity * _itemPrice;
   double discountFactor;
   if(basePrice > 1000) discountFactor = 0.95;
   else   discountFactor = 0.98;
   return basePrice * discountFactor;
}

 

首先我把赋值(assignment)动作的右侧表达式提炼出来:

 

double getPrice() {
   final int basePrice = basePrice();
   final double discountFactor;
   if(basePrice > 1000) discountFactor = 0.95;
   else   discountFactor = 0.98;
   return basePrice * discountFactor;
}
private int basePrice() {
   return _quantity * _itemPrice;
}

 

编译并测试,然后开始使用Inline Temp

 

double getPrice() {
   final double discountFactor;
   if(basePrice() > 1000) discountFactor = 0.95;
   else   discountFactor = 0.98;
   return basePrice() * discountFactor;
}

 

private int basePrice() {
   return _quantity * _itemPrice;
}

 

搞定basePrice之后,我再以类似办法提炼出一个discountFactor():

 

double getPrice() {
   final double discountFactor = discountFactor();
      return basePrice() * discountFactor;
}
private double discountFactor() {
   if(basePrice() > 1000) return 0.95;
   else   return 0.98;
}

 

最终,getPrice()变成了这样:

 


double getPrice() {
      return basePrice() * discountFactor();
}
 

 

### 如何在 Spark SQL 中设置和使用变量 在 Python 编写的 Spark 应用程序中,可以通过多种方式向 Spark SQL 查询传递参数。一种常见的方式是利用 `DataFrame` API 和字符串插值来动态构建查询语句。 对于简单的变量替换操作,可以采用如下方法: ```python from pyspark.sql import SparkSession # 创建 SparkSession 实例 spark = SparkSession.builder \ .appName("VariableExample") \ .master("local[*]") \ .getOrCreate() # 定义要使用的变量 my_variable_value = "exampleValue" # 使用 f-string 或 format 方法将变量嵌入到 SQL 字符串内 query_with_var = f""" SELECT * FROM my_table WHERE column_name = '{my_variable_value}' """ df_result = spark.sql(query_with_var) df_result.show() ``` 另一种更安全的方法是通过绑定参数的方式来防止 SQL 注入攻击: ```python from pyspark.sql import Row data = [("John",), ("Jane",)] rdd = spark.sparkContext.parallelize(data) peopleDF = rdd.map(lambda x: Row(name=x[0])).toDF() name_to_find = "John" filtered_df = peopleDF.createOrReplaceTempView("temp_people") safe_query = """ SELECT name FROM temp_people WHERE name LIKE ? """ result_df = spark.sql(safe_query.replace('?', "'" + name_to_find + "'")) result_df.show() ``` 值得注意的是,在某些情况下直接使用 `OFFSET` 子句可能会遇到不兼容的问题[^3];因此如果涉及到分页逻辑,则需考虑其他替代方案如基于窗口函数实现相同效果。 为了提高性能并减少网络传输开销,当需要频繁访问不变的数据集时可引入广播变量机制[^4]。这允许开发者预先加载较小规模却经常被引用的数据结构至各个工作节点上供后续任务调用而无需重复发送这些数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值