重构 demo篇
本文背景为学习重构一书中的一些信息的记录。
该篇以一个影片租赁为背景。通过一层层的重构,最终实现相对来说比较完美的代码。
文中经典语句摘要:
“如果它没有坏,就不要动它 。” 用来形容我们工作中一些比较古董级的代码,或许写的很烂,但是基本功能是OK的,对于一个团队leader来说,不会主张你去修改他,对于一个保守级的开发来说,也懒的去修改他,虽然你个人任务修改它出错的概率近乎为0,但是仍旧是近乎。只愿我能在工作中永远保持一个敬畏之心,而非畏惧之心。
1、第一版,较多的信息冗余在一起,相对书中的第一版已经有了一些提升,加上了个人在初步做的一些重构,怎么说哥也是写过两年代码的人。简单重构还是了解一些的。
用户类,定义用户的名称以及租赁了哪些影片
package com.woniu.refactoring; import java.util.Enumeration;
import java.util.Vector; public class Customer {
private String _name;
private Vector _rentals = new Vector(); public String getName() {
return _name;
}
public void setName(String _name) {
this._name = _name;
}
public Vector getRentals() {
return _rentals;
}
public void setRentals(Vector _rentals) {
this._rentals = _rentals;
} public String statement() {
double totalAmout = 0;
int frequentRenterPoints = 0;
Enumeration rentals = _rentals.elements();
String result = "Rental Record for " + getName() + "\n";
while(rentals.hasMoreElements()) {
double thisAmout = 0;
Rental each = (Rental) rentals.nextElement();
//这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO
// switch (each.getMovie().getPriceCode()) {
// case Movie.REGULAR:
// thisAmout += 2;
// if(each.getDaysRented() > 2) {
// thisAmout += (each.getDaysRented() - 2) * 1.5;
// }
// break;
// case Movie.NEW_RELEASE:
// thisAmout += each.getDaysRented() * 3;
// break;
//
// case Movie.CHILDENS:
// thisAmout += 1.5;
// if(each.getDaysRented() > 3) {
// thisAmout += (each.getDaysRented() - 3) * 1.5;
// }
// break;
// }
//上述方法,经过提炼后得到这个相对来说可以重用的一个函数amounFor
thisAmout = amountFor(each);
//这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO
// frequentRenterPoints ++;
// if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {
// frequentRenterPoints ++;
// }
//进过提炼后的积分计算方式
frequentRenterPoints = getFrequentRenterPoints(each);
result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmout) + "\n";
totalAmout += thisAmout; } result += "Amount owed is " + String.valueOf(totalAmout) + "\n";
result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";
return result;
}
/**
* 用于计算此次租赁产生的积分
* @param rental 租赁
* @return
*/
private int getFrequentRenterPoints(Rental rental) {
if((rental.getMovie().getPriceCode() == Movie.NEW_RELEASE) && rental.getDaysRented() > 1) {
return 2;//这里其实在最初我是没有想到可以直接用2来代替的
}
return 1;
} /**
* 用于计算此次租赁消费金额
* @param rental
* @return
*/
private double amountFor(Rental rental) {
double thisAmout = 0;
switch (rental.getMovie().getPriceCode()) {
case Movie.REGULAR:
thisAmout += 2;
if(rental.getDaysRented() > 2) {
thisAmout += (rental.getDaysRented() - 2) * 1.5;
}
break;
case Movie.NEW_RELEASE:
thisAmout += rental.getDaysRented() * 3;
break; case Movie.CHILDENS:
thisAmout += 1.5;
if(rental.getDaysRented() > 3) {
thisAmout += (rental.getDaysRented() - 3) * 1.5;
}
break;
}
return thisAmout;
} }
影片类,定义了影片的类型以及价格
package com.woniu.refactoring;
public class Movie {
public static final int CHILDENS = 2;
public static final int REGULAR = 0;
public static final int NEW_RELEASE = 1;
private String _title;
private int _priceCode;
public Movie(String title, int priceCode) {
_title = title;
priceCode = priceCode;
}
public int getPriceCode() {
return _priceCode;
}
public void setPriceCode(int _priceCode) {
this._priceCode = _priceCode;
}
public String getTitle() {
return _title;
}
}
租赁类,记录影片被租赁的时间以及影片信息
package com.woniu.refactoring;
public class Rental {
private Movie _movie;
private int _daysRented;
public Rental(Movie movie, int daysRented) {
_movie = movie;
_daysRented = daysRented;
}
public Movie getMovie() {
return _movie;
}
public int getDaysRented() {
return _daysRented;
}
}
第二版
由于在amountFor()方法中,并没有任何用户的信息,却在用户的类中实现了关于影片计算逻辑,金额的产生发生的位置应该是在租赁中产生的,因此,应该将其移至Rental中,使用(Move Mehtod)来进行处理。
用户类,封装了用户总消费额以及总积分的计算。同时,将关于租赁的单价计算与单积分计算进行了迁移。
package com.woniu.refactoring; import java.util.Enumeration;
import java.util.Vector; public class Customer {
private String _name;
private Vector _rentals = new Vector(); public String getName() {
return _name;
}
public void setName(String _name) {
this._name = _name;
}
public Vector getRentals() {
return _rentals;
}
public void setRentals(Vector _rentals) {
this._rentals = _rentals;
} public String statement() {
// double totalAmout = 0;
// int frequentRenterPoints = 0;
Enumeration rentals = _rentals.elements();
String result = "Rental Record for " + getName() + "\n";
while(rentals.hasMoreElements()) {
double thisAmout = 0;
Rental each = (Rental) rentals.nextElement();
//这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO
// switch (each.getMovie().getPriceCode()) {
// case Movie.REGULAR:
// thisAmout += 2;
// if(each.getDaysRented() > 2) {
// thisAmout += (each.getDaysRented() - 2) * 1.5;
// }
// break;
// case Movie.NEW_RELEASE:
// thisAmout += each.getDaysRented() * 3;
// break;
//
// case Movie.CHILDENS:
// thisAmout += 1.5;
// if(each.getDaysRented() > 3) {
// thisAmout += (each.getDaysRented() - 3) * 1.5;
// }
// break;
// }
//上述方法,经过提炼后得到这个相对来说可以重用的一个函数amounFor
// thisAmout = amountFor(each);
thisAmout = each.getCharge();//这是第二版的重构,将金额计算与积分计算,移至了Rental中,因为这是在租赁过程中产生的
//这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO
// frequentRenterPoints ++;
// if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {
// frequentRenterPoints ++;
// }
//进过提炼后的积分计算方式
// frequentRenterPoints = getFrequentRenterPoints(each);
// frequentRenterPoints = each.getFrequentRenterPoints();//这是第二版的重构,将金额计算与积分计算,移至了Rental中,因为这是在租赁过程中产生的
result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmout) + "\n";
// totalAmout += thisAmout;//2书中提到该处可以直接使用getCharge()获取金额,进而避免了局部变量的使用,但是,我没有找到关于多次计算的优化点,因此不敢王嘉苟同。 } result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";//对于总金额计算单独提取方法,以备后用
result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points";
return result;
} /**
* 获取用户消费的总金额
* @return
*/
private double getTotalCharge() {
double totalAmout = 0;
Enumeration rentals = _rentals.elements();
while(rentals.hasMoreElements()) {
Rental rental = (Rental)rentals.nextElement();
totalAmout += rental.getCharge();
}
return totalAmout;
} /**
* 获取用户消费的总积分
* @return
*/
private int getTotalFrequentRenterPoints() {
int result = 0;
Enumeration rentals = _rentals.elements();
while(rentals.hasMoreElements()) {
Rental rental = (Rental)rentals.nextElement();
result += rental.getFrequentRenterPoints();
}
return result;
} /**
* 用于计算此次租赁产生的积分
* @param rental 租赁
* @return
*/
@Deprecated
private int getFrequentRenterPoints(Rental rental) {
if((rental.getMovie().getPriceCode() == Movie.NEW_RELEASE) && rental.getDaysRented() > 1) {
return 2;//这里其实在最初我是没有想到可以直接用2来代替的
}
return 1;
} /**
* 用于计算此次租赁消费金额
* @param rental
* @return
*/
@Deprecated
private double amountFor(Rental rental) {
return rental.getCharge();//这里其实没必要再次进行封装函数了。可以直接在循环中使用rental的getCharge方法进行计算。
// double thisAmout = 0;
// switch (rental.getMovie().getPriceCode()) {
// case Movie.REGULAR:
// thisAmout += 2;
// if(rental.getDaysRented() > 2) {
// thisAmout += (rental.getDaysRented() - 2) * 1.5;
// }
// break;
// case Movie.NEW_RELEASE:
// thisAmout += rental.getDaysRented() * 3;
// break;
//
// case Movie.CHILDENS:
// thisAmout += 1.5;
// if(rental.getDaysRented() > 3) {
// thisAmout += (rental.getDaysRented() - 3) * 1.5;
// }
// break;
// }
// return thisAmout;
} }
租赁类,增加了关于租赁单价的计算以及积分计算。
package com.woniu.refactoring;
public class Rental {
private Movie _movie;
private int _daysRented;
public Rental(Movie movie, int daysRented) {
_movie = movie;
_daysRented = daysRented;
}
public Movie getMovie() {
return _movie;
}
public int getDaysRented() {
return _daysRented;
}
/**
* 用户此次租赁积分的计算
* @param rental
* @return
*/
public int getFrequentRenterPoints() {
if((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDaysRented() > 1) {
return 2;//这里其实在最初我是没有想到可以直接用2来代替的
}
return 1;
}
/**
* 用于计算此次租赁消费金额
* 2关于这个方法,其实应该是在租赁关系发生时,已经需要计算好金额了。这样就可以避免了Customer中提到的优化点,
* 但是,这样同样会造成如果交易取消了,我浪费资源进行了计算。
* @param rental
* @return
*/
public double getCharge() {
double thisAmout = 0;
switch (getMovie().getPriceCode()) {
case Movie.REGULAR:
thisAmout += 2;
if(getDaysRented() > 2) {
thisAmout += (getDaysRented() - 2) * 1.5;
}
break;
case Movie.NEW_RELEASE:
thisAmout += getDaysRented() * 3;
break;
case Movie.CHILDENS:
thisAmout += 1.5;
if(getDaysRented() > 3) {
thisAmout += (getDaysRented() - 3) * 1.5;
}
break;
}
return thisAmout;
}
}
原本到这里,我理解,此次重构已经结束了。但发现,后续还有新的重构方向。。。。。
重构 demo篇的更多相关文章
- 手把手制作一个简单的IDEA插件(环境搭建Demo篇)
新建IDEA插件File --> new --> Project--> Intellij PlatForm Plugin-->Next-->填好项目名OK 编写插件新建工 ...
- Feed流系统重构-架构篇
重构,于我而言,很大的快乐在于能够解决问题. 第一次重构是重构一个c#版本的彩票算奖系统.当时的算奖系统在开奖后,算奖经常超时,导致用户经常投诉.接到重构的任务,既兴奋又紧张,花了两天时间,除了吃饭睡 ...
- 复习 | 彻底弄懂Flexbox之Demo篇
flexbox之前有接触,写项目时也用过,但也只是简单的,对其也是似懂非懂,所以今天下定决心把这个再学一遍,因为似懂非懂就是不懂 本文主要是的demo演示,想看flexbox语法 请移步flexbox ...
- No.2一步步学习vuejs 实例demo篇
简单应用Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统: <div id="app"> {{ message }} </d ...
- selenium自动化(二).........................................Demo篇
二 编写简单代码 简单代码一: demo1.py 1.from selenium import webdriver driver = webdriver.Chrome() driver.get(& ...
- ABAP DEMO篇21 选择屏幕显示说明TEXT
实现方式1: *&---------------------------------------------------------------------**& Report YCX ...
- 【数据库】通过触发器实现审计日志记录-demo篇
触发器实现审计日志记录(记录增.删.改) #创建测试表 CREATE TABLE COMPANY( ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, ...
- 学习 | css3基本动画之demo篇
移动端使用的框架是zepto,但是zepto的内置对象没有传统的animate这个方法,效果都是需要css3来实现的,zepto也不支持fadeIn和fadeOut等一些基本的动画,基于这一现状,我自 ...
- http程序接口、调用(最入门级,文末附Demo)
HTTP协议简介 既然是基于HTTP协议开发,那么就首先要了解下HTTP协议的相关内容- 在TCP/IP体系结构中,HTTP属于应用层协议,位于TCP/IP协议的顶层.浏览Web时,浏览器通过HTTP ...
随机推荐
- 迅雷7 纯净版v7.9.18.4724
http://soft2.xzstatic.com/2016/08/Thunder_7.9.13.4666_NoAD_VIP.exe http://www.downza.cn/soft/192064. ...
- ISCC2016-BASIC、WEB、MISC简单writeup
RE和PWN题目的wp有大神已经放出来了,我也不擅长,就不搬了.bin求带. BASIC BASIC-1 50 仿射函数,百度“仿射加密法”,它讲的够清楚了. BASIC-2 50 结尾的“=”这个特 ...
- (转)WPF学习资源整理
由于笔者正在学习WPF,所以整理出网络中部分WPF的学习资源,希望对同样在学习WPF的朋友们有所帮助. 首推刘铁猛的<深入浅出WPF>系列博文 1.深入浅出WPF(1)——什么是WPFht ...
- hdu 5103 状态压缩dp
这题说的是给了n(14)个点,每个点都以他 为根的最大可容的孩子个数和最小的可溶孩子个数L[i] ,R[i] 问这n个点形成一棵树有多少种形态 我们让 dp[i][S] 表示 一 i为根节点 的 拥有 ...
- javascript数组总结
数组是一个有序的集合,javascript数组中的元素的类型可以是任意的,同一个数组不同元素之间的类型也是可以不同的.数组也是对象,有个length属性,记录数组的长度. 创建数组有两种方法: 数组直 ...
- 钉钉企业的CorpId 查看
打开钉钉开发者文档官网,注册一个账号(个人也可以注册),登陆账号之后在开发账号管理那里可以看到corpid(企业ID),corpsecret需要生成
- python基础之多线程锁机制
GIL(全局解释器锁) GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL 在Cpython解释器 ...
- Spring注解@Value
本文参考自: https://blog.csdn.net/ryelqy/article/details/77453713 @Value能让我们在java代码中使用property文件的属性,使用@Va ...
- 学习java的一点体会
在这几天的做实验.读书.写笔记的过程中我发现一个问题,就是我的知识面太窄,就比如说,学的知识都是一块一块的,没有能力去把它串起来,虽然学的很快,也写笔记总结,但马上就忘了,我想java是一个体系,需要 ...
- 20145204《java程序设计》课程总结
---恢复内容开始--- 20145204<java程序设计>课程总结 每周读书笔记链接汇总: · 20145204<java程序设计>第一周总结 · 20145204< ...