目录
这是一篇《重构 》的总结 ,我在学习的同时并使用它作为参考。这不是一本书的替代品,所以你要想真的想学习里面的内容,买一本书使用这个文章作为参考和指南。
另外: 建议 评论 还 PR 都是十分欢迎的
多个地方使用相同的代码
一个很长的程序是很难被理解的
当一个类变的越来越大的时候,是难以阅读的
长参数是很难去理解,不符合也较难使用
当一个类经常因为不同原因发生在不同的方向发生变化
每次你做一小部分修改时,都不的不需要做大量的修改在很多不同的类中
某个方法似乎在另外的类的兴趣高于自己所处的类
一堆数据杂糅在一起(字段, 参数)
使用基本类型替代小对象
当程序中出现很多 switch 语句在很多地方,使用多态来进行替换
每当你为一个类增加一个子类,你不得不为另一个类增加相应的一个子类
当一个类不足与为其自身买单它就应该被删除
所有的钩子和特殊情况处理那些不需要的
一个临时变量仅仅为某种特殊情况做而定,这样的代码让人难以理解
当一个类请求调用一个对象,但是这个类又在调用其他的方法
当一个对象委托大部分功能,开发中可能会过度的使用委托模式,导致某个类中的方法大都委托给其他方法处理
当两个类过度的亲密,需要将其拆散
类的方法过度相似
当我们使用外部依赖库时
不要操作数据类,我们通过封装它的不变性
子类不想使用父类的方法
当一个方法使用过度的注释解释其中的逻辑时,说明这个方法应该被重构了。
你可以将一些代码组合起来,然后放到一个方法中
void printOwing(double amount) {
printBanner();
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + amount);
}
to
void printOwing(double amount) {
printBanner();
printDetails(amount);
}
void printDetails (double amount) {
System.out.println ("name:" + _name);
System.out.println ("amount" + amount);
}
动机
void printOwing(double previousAmount) {
Enumeration e = _orders.elements();
double outstanding = previousAmount * 1.2;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
printDetails(outstanding);
}
to
void printOwing(double previousAmount) {
printBanner();
double outstanding = getOutstanding(previousAmount * 1.2);
printDetails(outstanding);
}
double getOutstanding(double initialValue) {
double result = initialValue;
Enumeration e = _orders.elements();
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result += each.getAmount();
}
return result;
}
一个函数本体和函数名称一样容易理解
int getRating() {
return (moreThanFiveLateDeliveries()) ? 2 : 1;
}
boolean moreThanFiveLateDeliveries() {
return _numberOfLateDeliveries > 5;
}
to
int getRating() {
return (_numberOfLateDeliveries > 5) ? 2 : 1;
}
动机
你申明了一个临时的变量在一段表达里面,然后临时的变量将会阻挡你重构
double basePrice = anOrder.basePrice();
return (basePrice > 1000)
to
return (anOrder.basePrice() > 1000)
Motivation
你正在使用临时变量来保存表达式的结果
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000){
return basePrice * 0.95;
}
else{
return basePrice * 0.98;
}
to
if (basePrice() > 1000){
return basePrice() * 0.95;
}
else{
return basePrice() * 0.98;
}
...
double basePrice() {
return _quantity * _itemPrice;
}
动机
有一个复杂的表达式
if ( (platform.toUpperCase().indexOf("MAC") > -1) &&
(browser.toUpperCase().indexOf("IE") > -1) &&
wasInitialized() && resize > 0 )
{
// do something
}
to
final boolean isMacOs = platform.toUpperCase().indexOf("MAC") >-1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") >-1;
final boolean wasResized = resize > 0;
if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
// do something
}
动机
你能有一个临时变量声明不止一次,但是它不是循环体中的变量或者要被存储的变量
double temp = 2 * (_height + _width);
System.out.println (temp);
temp = _height * _width;
System.out.println (temp);
to
final double perimeter = 2 * (_height + _width);
System.out.println (perimeter);
final double area = _height * _width;
System.out.println (area);
动机
下的代码将对参数进行了赋值
int discount (int inputVal, int quantity, int yearToDate) {
if (inputVal > 50) {
inputVal -= 2;
}
}
to
int discount (int inputVal, int quantity, int yearToDate) {
int result = inputVal;
if (inputVal > 50) {
result -= 2;
}
}
动机
将这个函数放进一个单独的对象,如此一来局部变量就变成对象内部的字段,然后你可以在同一个对象中将这个大型函数分解为多个小型函数
class Order...
double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// long computation;
...
}
to
class Order...
double price(){
return new PriceCalculator(this).compute()
}
}
class PriceCalculato...
compute(){
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// long computation;
return ...
}
动机
它的样本本不应该这样的重构,但是为显示这样做的方法
Class Account
int gamma (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;
}
}
to
class Gamma...
private final Account _account;
private int inputVal;
private int quantity;
private int yearToDate;
private int importantValue1;
private int importantValue2;
private int importantValue3;
Gamma (Account source, int inputValArg, int quantityArg, int yearToDateArg) {
_account = source;
inputVal = inputValArg;
quantity = quantityArg;
yearToDate = yearToDateArg;
}
int compute () {
importantValue1 = (inputVal * quantity) + _account.delta();
importantValue2 = (inputVal * yearToDate) + 100;
if ((yearToDate - importantValue1) > 100)
importantValue2 -= 20;
int importantValue3 = importantValue2 * 7;
// and so on.
return importantValue3 - 2 * importantValue1;
}
int gamma (int inputVal, int quantity, int yearToDate) {
return new Gamma(this, inputVal, quantity,yearToDate).compute();
}
你想更换一个更为清晰高效的算法
String foundPerson(String[] people){
for (int i = 0; i < people.length; i++) {
if (people[i].equals ("Don")){
return "Don";
}
if (people[i].equals ("John")){
return "John";
}
if (people[i].equals ("Kent")){
return "Kent";
}
}
return "";
}
to
String foundPerson(String[] people){
List candidates = Arrays.asList(new String[] {"Don", "John","Kent"});
for (int i = 0; i<people.length; i++)
if (candidates.contains(people[i]))
return people[i];
return "";
}
动机
在进行方法的初始定义的时候要想下以后会不会有其他的类也将会用到它
一个类它通常会创建一个新的简单的方法体, 同时它会将9?旧的方法做一个简单的委托或者移除它
class Class1 {
aMethod()
}
class Class2 { }
to
class Class1 { }
class Class2 {
aMethod()
}
动机
当一个类做了很多工作,或者这个类过度的耦合
当一个字段被定义的时候,可能不仅被不止一个类使用。
创建一个字段在一个目标类中,然后改变所有的拥有者
class Class1 {
aField
}
class Class2 { }
to
class Class1 { }
class Class2 {
aField
}
动机
如果一个字段被超过多个类引用
你有一个类,但是这个类做了它份外的事情
创建一个新的类,然后将相关字段移入到新的类中
class Person {
name,
officeAreaCode,
officeNumber,
getTelephoneNumber()
}
to
class Person {
name,
getTelephoneNumber()
}
class TelephoneNumber {
areaCode,
number,
getTelephoneNumber()
}
动机
类随着业务的增长在变化
在合适的时候进行分解它
一个其实没做多少事情的类
将这个类整合到另外一个类中,然后删除这个类
class Person {
name,
getTelephoneNumber()
}
class TelephoneNumber {
areaCode,
number,
getTelephoneNumber()
}
to
class Person {
name,
officeAreaCode,
officeNumber,
getTelephoneNumber()
}
动机
在重构的时候将这个类的基本信息移入到另外一个类中,然后在移除这个类
客户端其实调用的是对象的委托类
在服务端创建一个方法,然后隐藏这个委托类
class ClientClass {
//Dependencies
Person person = new Person()
Department department = new Department()
person.doSomething()
department.doSomething()
}
to
class ClientClass {
Person person = new Person()
person.doSomething()
}
class Person{
Department department = new Department()
department.doSomething()
}
解决方法
class ClientClass{
Server server = new Server()
server.doSomething()
}
class Server{
Delegate delegate = new Delegate()
void doSomething(){
delegate.doSomething()
}
}
//委托类其实隐藏在客户类里面
// 改变不会传播到客户端那边,因为它之后影响到服务端这边
class Delegate{
void doSomething(){...}
}
动机
关键在于封装
类应该尽量的使用其他的类
> manager = john.getDepartment().getManager();
class Person {
Department _department;
public Department getDepartment() {
return _department;
}
public void setDepartment(Department arg) {
_department = arg;
}
}
class Department {
private String _chargeCode;
private Person _manager;
public Department (Person manager) {
_manager = manager;
}
public Person getManager() {
return _manager;
}
...
to
> manager = john.getManager();
class Person {
...
public Person getManager() {
return _department.getManager();
}
}
一个类通过代理干了太多的事情
让客户直接调用委托
class ClientClass {
Person person = new Person()
person.doSomething()
}
class Person{
Department department = new Department()
department.doSomething()
}
to
class ClientClass {
//Dependencies
Person person = new Person()
Department department = new Department()
person.doSomething()
department.doSomething()
}
动机
当客户类使用过多的中间人调用委托的方法
一个类是引用的外部开源包,但是不能修改其内部的逻辑
创建一个新的方法在这个类中,并以第一个参数的形式传入一个服务类实例
Date newStart = new Date(previousEnd.getYear(),previousEnd.getMonth(),previousEnd.getDate()+1);
to
Date newStart = nextDay(previousEnd);
private static Date nextDay(Date date){
return new Date(date.getYear(),date.getMonth(),date.getDate()+1);
}
动机
当你使用一个类,这个类你又不能对其进行修改的时候可以采用这样方式
你需要为一个服务类提供一些额外的方法,但是你无法修改这个子类
创建一个新的类,使它包含这些额外的方法。这个扩展的类成为源类的子类或者包装类
class ClientClass(){
Date date = new Date()
nextDate = nextDay(date);
private static Date nextDay(Date date){
return new Date(date.getYear(),date.getMonth(),date.getDate()+1);
}
}
to
class ClientClass() {
MfDate date = new MfDate()
nextDate = nextDate(date)
}
class MfDate() extends Date {
...
private static Date nextDay(Date date){
return new Date(date.getYear(),date.getMonth(),date.getDate()+1);
}
}
动机
当我们使用 16. Introduce Foreign Method 我们需要在这个类中添加额外的方法
你可以直接获取对象,但是这样的话会变得越来越复杂
通过创建setting getting 方法来获取这些字段
private int _low, _high;
boolean includes (int arg) {
return arg >= _low && arg <= _high;
}
to
private int _low, _high;
boolean includes (int arg) {
return arg >= getLow() && arg <= getHigh();
}
int getLow() {return _low;}
int getHigh() {return _high;}
动机
允许子类可以覆盖如何get方法,并且这样的话它更加的支持灵活的管理,例如延迟加载
当你有个数据项需要进行添加数据或行为
将数据项转换为对象
class Order...{
private String _customer;
public Order (String customer) {
_customer = customer;
}
}
to
class Order...{
public Order (String customer) {
_customer = new Customer(customer);
}
}
class Customer {
public Customer (String name) {
_name = name;
}
}
动机
简单的数据对象并不简单
你有个类拥有很多单个对象,这些对象需要用一个单独的对象替代
将这个对象转换为引用对象
class Order...{
public Order (String customer) {
_customer = new Customer(customer);
}
}
class Customer {
public Customer (String name) {
_name = name;
}
}
to
//Use Factory Method
//使用工厂方法
class Customer...
static void loadCustomers() {
new Customer ("Lemon Car Hire").store();
new Customer ("Associated Coffee Machines").store();
new Customer ("Bilston Gasworks").store();
}
private void store() {
_instances.put(this.getName(), this);
}
public static Customer create (String name) {
return (Customer) _instances.get(name);
}
动机
引用对象是类似于消费者或者账单这样的对象,每个对象代表这一类对象在一个真实的世界,并使用对象表示来测试它们是否相同
你有一个有一个引用对象是很小,不变,难以管理的
将其转换为值对象
new Currency("USD").equals(new Currency("USD")) // returns false
to
new Currency("USD").equals(new Currency("USD")) // now returns true
动机
使用引用对象是变得越来月复杂,并且引用对象是不变和单一的。尤其在分布式和并发系统中
你拥有一个数组,其中这些元素是不同的
使用一个对象来替换这个数组,将数组的元素赋值在对象的属性上
String[] row = new String[3];
row [0] = "Liverpool";
row [1] = "15";
to
Performance row = new Performance();
row.setName("Liverpool");
row.setWins("15");
动机
数组应该被用在一些相似的集合对象序列中
可能你有一些domain数据是通过GUI控制的与此同时这些domain数据是需要访问的
往一些实体对象复制一些数据,通过设置观察者来同步两部分数据
动机
为了将代码从用户界面分解到业务处理层
你有两个对象,这两个对象需要使用对方的特征属性,但是目前只有一种连接方式
添加返回指针,然后更改修饰符已更改两个对象
class Order...
Customer getCustomer() {
return _customer;
}
void setCustomer (Customer arg) {
_customer = arg;
}
Customer _customer;
}
to
class Order...
Customer getCustomer() {
return _customer;
}
void setCustomer (Customer arg) {
if (_customer != null) _customer.friendOrders().remove(this);
_customer = arg;
if (_customer != null) _customer.friendOrders().add(this);
}
private Customer _customer;
class Customer...
void addOrder(Order arg) {
arg.setCustomer(this);
}
private Set _orders = new HashSet();
Set friendOrders() {
/** should only be used by Order */
return _orders;
}
}
}
// Many to Many
class Order... //controlling methods
void addCustomer (Customer arg) {
arg.friendOrders().add(this);
_customers.add(arg);
}
void removeCustomer (Customer arg) {
arg.friendOrders().remove(this);
_customers.remove(arg);
}
class Customer...
void addOrder(Order arg) {
arg.addCustomer(this);
}
void removeOrder(Order arg) {
arg.removeCustomer(this);
}
}
动机
当对象引用需要互相引用的时候,你应该采用这种方法
当你有个双向联系的类,但是在后期一个类不在需要另一个类中的属性了
扔掉不需要的联系
动机
当双向联系不在需要,减少复杂度,移除僵尸对象,消除相互依赖
你有一个特定含义的字符串
创建一个常量,名称根据它的意思命名然后替换那个数字
double potentialEnergy(double mass, double height) {
return mass * 9.81 * height;
}
to
double potentialEnergy(double mass, double height) {
return mass * GRAVITATIONAL_CONSTANT * height;
}
static final double GRAVITATIONAL_CONSTANT = 9.81;
动机
避免使用魔法数字
这里有一个公共的字段
将它改为私有的并提供访问函数
public String _name
to
private String _name;
public String getName() {
return _name;
}
public void setName(String arg) {
_name = arg;
}
动机
你应该将你数据公开
一个返回几个的方法
确保返回一个只读的影像对象,然后提供添加和移除方法
class Person {
Person (String name){
HashSet set new HashSet()
}
Set getCourses(){}
void setCourses(:Set){}
}
to
class Person {
Person (String name){
HashSet set new HashSet()
}
Unmodifiable Set getCourses(){}
void addCourses(:Course){}
void removeCourses(:Course){}
}
动机
你必须面对一个记录值在传统的编程环境中
使用一个僵尸数据对象代替记录值
动机
一个类拥有数字类别码,不能影响其行为
使用类来代替数字
class Person{
O:Int;
A:Int;
B:Int;
AB:Int;
bloodGroup:Int;
}
to
class Person{
bloodGroup:BloodGroup;
}
class BloodGroup{
O:BloodGroup;
A:BloodGroup;
B:BloodGroup;
AB:BloodGroup;
}
动机
静态类别检查
在一个类中拥有一个不变的类型码影响整个类的行为
使用子类来替代这个不变的类型码
class Employee...
private int _type;
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
Employee (int type) {
_type = type;
}
}
to
abstract int getType();
static Employee create(int type) {
switch (type) {
case ENGINEER:
return new Engineer();
case SALESMAN:
return new Salesman();
case MANAGER:
return new Manager();
default:
throw new IllegalArgumentException("Incorrect type code value");
}
}
动机
在类中有个类型码,并通过这个类型码来影响行为,但是你不能使用子类
通过状态对象来代替这个类型码
class Employee {
private int _type;
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
Employee (int type) {
_type = type;
}
int payAmount() {
switch (_type) {
case ENGINEER:
return _monthlySalary;
case SALESMAN:
return _monthlySalary + _commission;
case MANAGER:
return _monthlySalary + _bonus;
default:
throw new RuntimeException("Incorrect Employee");
}
}
}
}
to
class Employee...
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
void setType(int arg) {
_type = EmployeeType.newType(arg);
}
class EmployeeType...
static EmployeeType newType(int code) {
switch (code) {
case ENGINEER:
return new Engineer();
case SALESMAN:
return new Salesman();
case MANAGER:
return new Manager();
default:
throw new IllegalArgumentException("Incorrect Employee Code");
}
}
}
int payAmount() {
switch (getType()) {
case EmployeeType.ENGINEER:
return _monthlySalary;
case EmployeeType.SALESMAN:
return _monthlySalary + _commission;
case EmployeeType.MANAGER:
return _monthlySalary + _bonus;
default:
throw new RuntimeException("Incorrect Employee");
}
}
}
动机
你的子类仅在返回常数变量数据变量的方法中有所不同
将这个方法提升到父类中,并移除这个子类
abstract class Person {
abstract boolean isMale();
abstract char getCode();
...
}
class Male extends Person {
boolean isMale() {
return true;
}
char getCode() {
return ‘M‘;
}
}
class Female extends Person {
boolean isMale() {
return false;
}
char getCode() {
return ‘F‘;
}
}
to
class Person{
protected Person (boolean isMale, char code) {
_isMale = isMale;
_code = code;
}
boolean isMale() {
return _isMale;
}
static Person createMale(){
return new Person(true, ‘M‘);
}
static Person createFemale(){
return new Person(false, ‘F‘);
}
}
动机
你有一个复杂的条件(大量的if else then )
使用额外的方法代替这个表达式,将then 放在一部分,else 放在一部分
if (date.before (SUMMER_START) || date.after(SUMMER_END))
charge = quantity * _winterRate + _winterServiceCharge;
else
charge = quantity * _summerRate;
to
if (notSummer(date))
charge = winterCharge(quantity);
else
charge = summerCharge (quantity);
动机
double disabilityAmount() {
if (_seniority < 2) return 0;
if (_monthsDisabled > 12) return 0;
if (_isPartTime) return 0;
// compute the disability amount
to
double disabilityAmount() {
if (isNotEligableForDisability()) return 0;
// compute the disability amount
在条件表达式的每个分支上有着相同的一片代码
将这段重复代搬移到条件表达式之外
if (isSpecialDeal()) {
total = price * 0.95;
send();
}
else {
total = price * 0.98;
send();
}
to
if (isSpecialDeal()) {
total = price * 0.95;
}
else {
total = price * 0.98;
}
send();
动机
使得变量清晰并保持相同
在一系列的布尔表达式中,某个变量带有“控制标记”的作用
已break或者return语句取代控制标记
void checkSecurity(String[] people) {
boolean found = false;
for (int i = 0; i < people.length; i++) {
if (! found) {
if (people[i].equals ("Don")){
sendAlert();
found = true;
}
if (people[i].equals ("John")){
sendAlert();
found = true;
}
}
}
}
to
void checkSecurity(String[] people) {
for (int i = 0; i < people.length; i++) {
if (people[i].equals ("Don")){
sendAlert();
break; // or return
}
if (people[i].equals ("John")){
sendAlert();
break; // or return
}
}
}
动机
break
和 continue
函数的条件逻辑使人难以看清正常的执行路径
使用卫语句表现所有的特殊情况
double getPayAmount() {
double result;
if (_isDead) result = deadAmount();
else {
if (_isSeparated) result = separatedAmount();
else {
if (_isRetired) result = retiredAmount();
else result = normalPayAmount();
};
}
return result;
};
to
double getPayAmount() {
if (_isDead) return deadAmount();
if (_isSeparated) return separatedAmount();
if (_isRetired) return retiredAmount();
return normalPayAmount();
};
动机
你手上有一个条件表达式,它根据对象的类型的不同选择不同的行为
将条件表达式的所有分支放进一个子类内的覆盖函数中,然后将原始函数声明为抽象函数
class Employee {
private int _type;
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
Employee (int type) {
_type = type;
}
int payAmount() {
switch (_type) {
case ENGINEER:
return _monthlySalary;
case SALESMAN:
return _monthlySalary + _commission;
case MANAGER:
return _monthlySalary + _bonus;
default:
throw new RuntimeException("Incorrect Employee");
}
}
}
}
to
class Employee...
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
void setType(int arg) {
_type = EmployeeType.newType(arg);
}
int payAmount() {
return _type.payAmount(this);
}
}
class Engineer...
int payAmount(Employee emp) {
return emp.getMonthlySalary();
}
}
动机
你不得不检查对象是否为Null对象
将null值替换为null对象
if (customer == null){
plan = BillingPlan.basic();
}
else{
plan = customer.getPlan();
}
to
class Customer {
}
class NullCusomer extends Customer {
}
动机
某段代码需要对程序状态做出某种假设
已断言明确表现这种假设
double getExpenseLimit() {
// should have either expense limit or a primary project
return (_expenseLimit != NULL_EXPENSE) ?
_expenseLimit:
_primaryProject.getMemberExpenseLimit();
}
to
double getExpenseLimit() {
Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null);
return (_expenseLimit != NULL_EXPENSE) ?
_expenseLimit:
_primaryProject.getMemberExpenseLimit();
}
动机
函数的名称不能表达函数的用途
修改函数名称
getinvcdtlmt()
to
getInvoiceableCreditLimit
动机
函数的名称最好能表达函数的意图
某个函数需要从调用端得到更多的信息
为此函数添加一个对象函数,让改对象带进函数所需要信息
getContact()
to
getContact(:Date)
动机
在改变方法之后,你获得更多的信息
一个参数不在函数中使用了
移除它
getContact(:Date)
to
getContact()
动机
一个参数不再使用还留着它干嘛?
某个函数即返回函数的状态值,又修改对象的状态
创建两个不同的函数,其中一个负责查询,另一个负责修改
getTotalOutStandingAndSetReadyForSummaries()
to
getTotalOutStanding()
SetReadyForSummaries()
动机
将有副作用的方法和没有副作用的方法分开
若干函数做了类似的工作,但在函数本体中却包含了不同的值
创建单一函数,已参数表达那些不同的值
fivePercentRaise()
tenPercentRaise()
to
raise(percentage)
动机
移除重复的代码提高灵活度
??一个函数,其中完全取决于参数值而采取不同的行为
针对该函数的每一个可能值,建立一个独立函数
void setValue (String name, int value) {
if (name.equals("height")){}
_height = value;
return;
}
if (name.equals("width")){
_width = value;
return;
}
Assert.shouldNeverReachHere();
}
to
void setHeight(int arg) {
_height = arg;
}
void setWidth (int arg) {
_width = arg;
}
动机
你从某个对象支行取出若干值,将他们作为某一次函数调用时的参数
改为传递一整个对象
int low = daysTempRange().getLow();
int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);
to
withinPlan = plan.withinRange(daysTempRange());
动机
对象调用某个函数,并将其所得的结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用钱一个函数
将函数接受者去除该项参数,并直接调用前一个函数
int basePrice = _quantity * _itemPrice;
discountLevel = getDiscountLevel();
double finalPrice = discountedPrice (basePrice, discountLevel);
to
int basePrice = _quantity * _itemPrice;
double finalPrice = discountedPrice (basePrice);
动机
某些参数总是很自然的同时出现
以一个对象取代这些参数
class Customer{
amountInvoicedIn (start : Date, end : Date)
amountReceivedIn (start : Date, end : Date)
amountOverdueIn (start : Date, end : Date)
}
to
class Customer{
amountInvoicedIn (: DateRange)
amountReceivedIn (: DateRange)
amountOverdueIn (: DateRange)
}
动机
类中的某个字段应该在对象创建时被设值,然后就不再改变
去掉该字段的所有设值函数
class Employee{
setImmutableValue()
}
to
class Employee{
ˉ\_(ツ)_/ˉ
}
动机
确保你的清晰的目的 : 如果你想你的字段在创建之后就不要被改变了,你就不应该提供一个setting方法用于确保你的字段是否不被改变的
有一个函数,从来没有被其他任何类用到
将这个函数修改为 private
class Employee{
public method()
}
to
class Employee{
private method()
}
动机
如果一个方法不需要被外部调用,那么就应该讲这个方法隐藏
在创建对象时不仅仅是做简单的健够动作
将构造函数替换为工厂函数
Employee (int type) {
_type = type;
}
to
static Employee create(int type) {
return new Employee(type);
}
创建一个对象依赖于其子类,构造函数只能返回单一类型的对象,因此你需要将构造函数替换为一个工厂函数
某个函数返回的对象,需要由调用者执行向下转型
将向下转型动作转移到函数中
Object lastReading() {
return readings.lastElement();
}
to
Reading lastReading() {
return (Reading) readings.lastElement();
}
动机
将一个方法最有效的返回值进行返回给函数的调用者
如果类型是准确的,检查使用这个对象的方法并提供一个更为有效的方法
某个函数返回一个特定的代码,用以表示某种错误情况
改用异常将其抛出去
int withdraw(int amount) {
if (amount > _balance)
return -1;
else {
_balance -= amount;
return 0;
}
}
to
void withdraw(int amount) throws BalanceException {
if (amount > _balance)
throw new BalanceException();
_balance -= amount;
}
动机
当一个程序在发生了一个不可处理的错误时,你需要使这个函数的调用者知道。向上抛出异常,让上层调用者知道
面对一个调用者可以预先检查的条件,你抛出了一个异常
修改调用者,使它在调用函数之前先做检查
double getValueForPeriod (int periodNumber) {
try {
return _values[periodNumber];
} catch (ArrayIndexOutOfBoundsException e) {
return 0;
}
}
to
double getValueForPeriod (int periodNumber) {
if (periodNumber >= _values.length)
return 0;
return _values[periodNumber];
}
动机
两个子类拥有相同的字段
将该字段移到超类中
class Salesman extends Employee{
String name;
}
class Engineer extends Employee{
String name;
}
to
class Employee{
String name;
}
class Salesman extends Employee{}
class Engineer extends Employee{}
动机
你在各个子类中拥有一些构造函数,他们的本体几乎完全一致
在超类中新建一个构造函数,并在子类构造函数中调用它
class Salesman extends Employee{
String getName();
}
class Engineer extends Employee{
String getName();
}
to
class Employee{
String getName();
}
class Salesman extends Employee{}
class Engineer extends Employee{}
动机
在子类中的构造函数与父类中的构造函数是相同的
在超类中创建一个构造函数,并在子类构造函数中调用它
class Manager extends Employee...
public Manager (String name, String id, int grade) {
_name = name;
_id = id;
_grade = grade;
}
to
public Manager (String name, String id, int grade) {
super (name, id);
_grade = grade;
}
动机
父类的某个方法至于某个子类相关
将其移到子类中
class Employee{
int getQuota();
}
class Salesman extends Employee{}
class Engineer extends Employee{}
to
class Salesman extends Employee{
int getQuota();
}
class Engineer extends Employee{}
动机
当方法只在子类中显现
超类的字段只在某个子类中用到
将这个字段移到需要它的那些子类中去
class Employee{
int quota;
}
class Salesman extends Employee{}
class Engineer extends Employee{}
to
class Salesman extends Employee{
int quota;
}
class Engineer extends Employee{}
动机
当一个字段只在子类中使用时
类中的某些特性只被某些实例用到
新建一个子类,将上面所说的那一部分特性移到子类中去
class JobItem {
getTotalPrices()
getUnitPrice()
getEmployee()
}
to
JobItem {
getTotalPrices()
getUnitPrice()
}
class class LabotItem extends JobItem {
getUnitPrice()
getEmployee()
}
动机
当一个类的行为只用在某些实例中而不用在其他类中
两个类具有相似特性
创建一个父类,然后将这两个类中相同的部分移到父类中,然后在继承这个父类
class Department{
getTotalAnnualCost()
getName()
getHeadCount
}
class Employee{
getAnnualCost()
getName()
getId
}
to
class Party{
getAnnualCost()
getName()
}
class Department {
getAnnualCost()
getHeadCount
}
class Employee {
getAnnualCost()
getId
}
动机
当两个类有过多相似的地方的时候,就需要考虑下是否需要将这个类进行下抽象了
若干客户使用类接口中的同一个子类,或者两个类的接口有相同的部分
将相同的子集提炼到一个独立接口中
class Employee {
getRate()
hasSpecialSkill()
getName()
getDepartment()
}
to
interface Billable {
getRate()
hasSpecialSkill()
}
class Employee implements Billable {
getRate
hasSpecialSkill()
getName()
getDepartment()
}
动机
超类和子类无太大区别
将它们合为一个
class Employee{ }
class Salesman extends Employee{ }
to
class Employee{ }
动机
该子类没有带来任何价值
有些子类,其中对应的某些函数以相同顺序执行类似的操作,但各个操作的细节上有所不同
将这些操作分别放进独立函数中,并保持它们都有相同的签名,于是原函数也就变得相同了。然后将原函数上移到超类
class Site{}
class ResidentialSite extends Site{
getBillableAmount()
}
class LifelineSite extends Site{
getBillableAmount()
}
to
class Site{
getBillableAmount()
getBaseAmount()
getTaxAmount()
}
class ResidentialSite extends Site{
getBaseAmount()
getTaxAmount()
}
class LifelineSite extends Site{
getBaseAmount()
getTaxAmount()
}
动机
某个子类只使用了超类接口中的一部分,或是根本不需要继承而来的数据
_在子类中创建一个字段用以保存超类,调整子类函数,令它改2而委托超类:然后去除两者之间的继承关系
class Vector{
isEmpty()
}
class Stack extends Vector {}
to
class Vector {
isEmpty()
}
class Stack {
Vector vector
isEmpty(){
return vector.isEmpty()
}
}
动机
你在两个类之间使用简单的委托关系,并经常为整个接口编写许多很多简单的委托函数
让委托类继承委托类
class Person {
getName()
}
class Employee {
Person person
getName(){
return person.getName()
}
}
to
class Person{
getName()
}
class Employee extends Person{}
动机
某个继承体系同时承担两项责任
建立两个继承体系,并通过委托关系让其中一个可以调用另外一个
class Deal{}
class ActiveDeal extends Deal{}
class PassiveDeal extends Deal{}
class TabularActiveDeal extends ActiveDeal{}
class TabularPassiveDeal extends PassiveDeal{}
to
class Deal{
PresentationStyle presettationStyle;
}
class ActiveDeal extends Deal{}
class PassiveDeal extends Deal{}
class PresentationStyle{}
class TabularPresentationStyle extends PresentationStyle{}
class SinglePresentationStyle extends PresentationStyle{}
动机
你手上有些传统过程化风格的代码
将数据记录变成对象,将大块的行为分成小块,并将行为移入相关对象中
class OrderCalculator{
determinePrice(Order)
determineTaxes(Order)
}
class Order{}
class OrderLine{}
to
class Order{
getPrice()
getTaxes()
}
class OrderLine{
getPrice()
getTaxes()
}
动机
使用面向对象思想进行变成
某些GUI类中包含了领域逻辑
将领域逻辑分离出来吗,为他们创建独立的领域类
class OrderWindow{}
to
class OrderWindow{
Order order;
}
动机
有某个类做了太多的工作其中一部分工作是以大量的条件表达式完成的
创建一个继承体系,已一个子类来表达某一种特殊的情况
class BillingScheme{}
to
class BillingScheme{}
class BusinessBillingScheme extends BillingScheme{}
class ResidentialBillingScheme extends BillingScheme{}
class DisabilityBillingScheme extends BillingScheme{}
动机
原文:https://www.cnblogs.com/wangshouchang/p/9780732.html