目录java
这是一篇《重构 》的总结 ,我在学习的同时并使用它做为参考。这不是一本书的替代品,因此你要想真的想学习里面的内容,买一本书使用这个文章做为参考和指南。git
另外: 建议 评论 还 PR 都是十分欢迎的github
多个地方使用相同的代码算法
一个很长的程序是很难被理解的数据库
当一个类变的愈来愈大的时候,是难以阅读的express
长参数是很难去理解,不符合也较难使用编程
当一个类常常由于不一样缘由发生在不一样的方向发生变化数组
每次你作一小部分修改时,都不的不须要作大量的修改在不少不一样的类中session
某个方法彷佛在另外的类的兴趣高于本身所处的类架构
一堆数据杂糅在一块儿(字段, 参数)
使用基本类型替代小对象
当程序中出现不少 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{}
动机