博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
31天重构学习笔记(java版本)
阅读量:6312 次
发布时间:2019-06-22

本文共 31451 字,大约阅读时间需要 104 分钟。

准备下周分享会的内容,无意间看到.net版本的重构31天,花了两个小时看了下,可以看成是Martin Fowler《重构》的精简版

原文地址:http://www.lostechies.com/blogs/sean_chambers/archive/2009/07/31/31-days-of-refactoring.aspx

原文代码地址:https://github.com/schambers/days-of-refactoring

写的.net版本的读书笔记地址:http://www.cnblogs.com/KnightsWarrior/p/31DaysOfRefactoring.html

有百度文库的可以直接下载:http://wenku.baidu.com/view/27423a5c3b3567ec102d8a0c.html?pn=51

 

抽个时间(就这周六吧,不过得先把分享会的PPT写好 囧),把java版本的写下,先mark下

周六总算是写完了,不过还想是多跨了一周 囧。有时间,在加下描点,还有pdf下载吧。累,回家咯 ^^ --20151114 


 

1.集合的封装

/** * @title 封装集合对象,不要暴露太多方法给外部访问内部数据 * @desc * @atuh lwx * @createtime on 2015/11/12 23:50 */public class Day_1 {    public static void main(String[] args) {        Day1Test day1Test = new Day1Test();        //获取到了内部对象        List
list = day1Test.getList(); //肆无忌惮的操作 list.add("a"); day1Test.iterator(); //正确的做法 Day1Test2 day1Test2 = new Day1Test2(); //获取到了内部对象 List
list2 = day1Test2.getList(); //肆无忌惮的操作 list2.add("a"); day1Test2.iterator(); } static class Day1Test { private List
list = new ArrayList
(); public List getList() { return list; } //模拟不暴露给外部 protected void add(String value) { list.add(value); } protected void remove(String value) { list.remove(value); } public void iterator() { for (String str : list) { System.out.println(str); } } } static class Day1Test2 { private List
list = new ArrayList
(); public List getList() { return new ArrayList(list); } //模拟不暴露给外部 protected void add(String value) { list.add(value); } protected void remove(String value) { list.remove(value); } public void iterator() { for (String str : list) { System.out.println(str); } } }}

 2.移动方法

Move method does exactly what it sounds like, move a method to a better location(移动方法到更合适的位置)

public class Day_2 {    public static void main(String[] args) {    }} class BankAccount1{    public BankAccount1(int accountAge, int creditScore, AccountInterest1 accountInterest)    {        AccountAge = accountAge;        CreditScore = creditScore;        AccountInterest1 = accountInterest;    }    public int AccountAge ;    public int CreditScore;    public AccountInterest1 AccountInterest1 ;} class AccountInterest1{    public BankAccount1 Account ;    public AccountInterest1(BankAccount1 account)    {        Account = account;    }    public double InterestRate()    {        return CalculateInterestRate();    }    public boolean IntroductoryRate()    {       return CalculateInterestRate() < 0.05;    }    public double CalculateInterestRate()    {        if (Account.CreditScore > 800)            return 0.02;        if (Account.AccountAge > 10)            return 0.03;        return 0.05;    }}class BankAccount {    public BankAccount(int accountAge, int creditScore, AccountInterest accountInterest) {        AccountAge = accountAge;        CreditScore = creditScore;        AccountInterest = accountInterest;    }    public int AccountAge;    public int CreditScore;    public AccountInterest AccountInterest;    //这个方法跟BankAccount没有直接关系    public double CalculateInterestRate() {        if (CreditScore > 800)            return 0.02;        if (AccountAge > 10)            return 0.03;        return 0.05;    }}class AccountInterest {    public BankAccount Account;    public AccountInterest(BankAccount account) {        Account = account;    }    public double InterestRate() {        return Account.CalculateInterestRate();    }    public boolean IntroductoryRate() {        {            return Account.CalculateInterestRate() < 0.05;        }    }}

 3.提升方法

简单点说,如果子类都有相同的方法,那就应该将方法提上到父类层

abstract class Vehicle {        // other methods    }    class Car extends Vehicle {        public void Turn(String str) {            // code here        }    }    public class Motorcycle extends Vehicle {        public void Turn(String str) {            // code here        }    }

提升后的结构

abstract class Vehicle1 {        public void Turn(String str) {            // code here        }    }    class Car1 extends Vehicle1 {          }    public class Motorcycle1 extends Vehicle1 {    }

4.下移方法

与第三个上升方法相比,有时候,父类的方法,随着业务的变化,只适合部分子类的时候,则需要将父类的方法下移到具体需要的子类中,这样才符合接口最小原则^^

abstract class Animal {        //狗吠        public void Bark() {            // code to bark        }    }    class Dog extends Animal {    }    class Cat extends Animal {    }

正常小猫是不会狗吠的,当然,有些接口可能当初定义的时候,有些子类还未出现,因此不会有这样的问题。随着业务的增加,这样的问题出现了,那么,我们就要及时的将接口下移

abstract class Animal1 {            }    class Dog1 extends Animal1 {        //狗吠        public void Bark() {            // code to bark        }    }    class Cat1 extends Animal1 {    }

5.提升字段

同提升方法,思路一样的,就不多说了

abstract class Account {    }    public class CheckingAccount extends Account {        private int _minimumCheckingBalance = 5;    }    public class SavingsAccount extends Account {        private int _minimumSavingsBalance = 5;    }

上升后的结构

abstract class Account1 {        protected int _minimumCheckingBalance = 5;    }        public class CheckingAccount1 extends Account1 {            }    public class SavingsAccount1 extends Account1 {    }

6.下移字段

abstract class Task {        protected String _resolution;    }    public class BugTask extends Task {    }    public class FeatureTask extends Task {    }

改造后的情况

abstract class Task1 {    }     class BugTask1 extends Task1 {        protected String _resolution;    }     class FeatureTask1 extends Task1 {    }

 7.重命名(类、方法、参数)

demo就不上,只提一点,命名规则不要担心太长,而选择简写,这样反而为后期的维护带来麻烦。

8.使用委托代替继承

设计模式中,很多模式就使用了委托的方式,来解耦继承带来的强依赖,比如装饰者,适配器模式等等。

class Sanitation {        public String WashHands() {            return "Cleaned!";        }    }    public class Child extends Sanitation {    }

正确的做法

class Sanitation1 {        public String WashHands() {            return "Cleaned!";        }    }    class Child1 {        private Sanitation1 Sanitation;        public Child1() {            Sanitation = new Sanitation1();        }        public String WashHands() {            return Sanitation.WashHands();        }    }

上述其实就是代理者模式的框架思路了,如果把Sanitation1暴露出来,就是装饰者了。

9.提取接口

官方已经找不到这个页面的链接了,参考了其他地方,做法其实也很简单,就是遵循了接口最小原则来设计的

interface Bird {        public void eat();        public void fly();        //我们假设有的鸟是不会唱歌的        public void song();    }

重新设计后

interface Bird1 {        public void eat();        public void fly();    }    interface SongBird extends Bird1 {        //我们假设有的鸟是不会唱歌的        public void song();    }

10.提取方法

 提取方法是重构中很常见到的一种手法。他可以通过方法名,增加代码的可读性,减少不必要的注释说明。

class Receipt {        private List
discounts; private List
itemTotals; public float CalculateGrandTotal() { float subTotal = 0f; for (Float itemTotal : itemTotals) subTotal += itemTotal; if (discounts.size() > 0) { for (Float discount : discounts) subTotal -= discount; } float tax = subTotal * 0.065f; subTotal += tax; return subTotal; } }

使用分离方法后的结构

class Receipt1 {        private List
discounts; private List
itemTotals; public float CalculateGrandTotal() { float subTotal = 0f; subTotal=addItemTotals(itemTotals); subTotal=minuteDiscounts(itemTotals); subTotal=calcTax(subTotal); return subTotal; } float addItemTotals(List
itemTotals){ float subTotal = 0f; for (Float itemTotal : itemTotals) { subTotal += itemTotal; } return subTotal; } float minuteDiscounts(List
discounts){ float subTotal = 0f; if (discounts.size() > 0) { for (Float discount : discounts) subTotal -= discount; } return subTotal; } float calcTax( float subTotal){ float tax = subTotal * 0.065f; subTotal += tax; return subTotal; } }

 11.切换到策略模式

很多时候,要完成目标的方式不是只有一种,当我们需要使用不同的条件,来获取不同的结果的时候,我们可以使用策略模式,这样,不会因为新增加一个条件,而去修改判断逻辑

public class ClientCode {        public int CalculateShipping() {            ShippingInfo shippingInfo = new ShippingInfo();            return shippingInfo.CalculateShippingAmount(State.Alaska);        }    }    public enum State {        Alaska,        NewYork,        Florida;    }    public class ShippingInfo {        public int CalculateShippingAmount(State shipToState) {            if (shipToState == State.Alaska) {                return GetAlaskaShippingAmount();            } else if (shipToState == State.NewYork) {                return GetNewYorkShippingAmount();            } else if (shipToState == State.Florida) {                return GetFloridaShippingAmount();            } else                return 0;        }    }    private int GetAlaskaShippingAmount() {        return 15;    }    private int GetNewYorkShippingAmount() {        return 10;    }    private int GetFloridaShippingAmount() {        return 3;    }

如果判断条件足够简单,上述做法,其实是可以容忍的,但是,如果Getxx方法变的足够复杂的时候,考虑到单一责任原则,一个类的变化,有且只有一个原因引起,这样,每个判断条件方法发生变化,类都必须做出修改,

这样就不合适了。而且使用类封装,可以更好的实现复用。

static class ShippingInfo1{        //模拟一个工厂        private static Map
strategyFactory=new HashMap
(); static { strategyFactory.put(State.Alaska,new GetAlaskaShippingAmount()); strategyFactory.put(State.NewYork,new GetNewYorkShippingAmount()); strategyFactory.put(State.Florida,new GetFloridaShippingAmount()); } public int CalculateShippingAmount(State shipToState) { return strategyFactory.get(shipToState).calc(); } } interface CalculateShippingAmountStrategy{ public int calc(); } static class GetAlaskaShippingAmount implements CalculateShippingAmountStrategy{ public int calc(){ return 15; } } static class GetNewYorkShippingAmount implements CalculateShippingAmountStrategy{ public int calc(){ return 10; } } static class GetFloridaShippingAmount implements CalculateShippingAmountStrategy{ public int calc(){ return 3; } }

12.解耦依赖

六大设计原则中的最少知识原则(迪米特)说的就是,对依赖的了解,降低到最少。作者强调,当我们进行单元测试的时候,我们就需要一定的隔离,否则无法进行mock.这个自己也是深有体会。

良好的隔离,确实可以让单元测试的Mock变得非常的简单和容易。先看下面的例子,由于AnimalFeedingService直接依赖了静态类Feeder,因此当我们需要只测试FoodBowlEmpty的逻辑判断走向的时候,必然会触发

Feeder的方法,这其实并不是我们想要的。但是又无法直接对静态类进行mock.

public class AnimalFeedingService    {        private boolean FoodBowlEmpty;        public void Feed()        {            if (FoodBowlEmpty)                Feeder.ReplenishFood();            // more code to feed the animal        }    }    public static class Feeder    {        public static void ReplenishFood()        {            // fill up bowl        }    }

解决的办法,就是让Service跟静态的对象解耦

public class AnimalFeedingService1    {        public IFeederService FeederService ;        public AnimalFeedingService1(IFeederService feederService)        {            FeederService = feederService;        }        private boolean FoodBowlEmpty ;        public void Feed()        {            if (FoodBowlEmpty)                FeederService.ReplenishFood();            // more code to feed the animal        }    }    public interface IFeederService    {        void ReplenishFood();    }    public class FeederService implements IFeederService    {        public void ReplenishFood()        {            Feeder.ReplenishFood();        }    }

13.提取方法对象

这并不是一种很常见的重构手段,即当我们对象中定义了很多变量,及其需要利用这些变量进行一些业务操作的时候,可以考虑将方法提取到一个新的类中,这样就解耦了变量与逻辑操作的直接关联。

也比较符合单一责任原则。

public class OrderLineItem    {        public int Price ;    }    public class Order    {        private List
OrderLineItems ; private List
Discounts; private int Tax ; public int Calculate() { int subTotal = 0; // Total up line items for (OrderLineItem lineItem : OrderLineItems) { subTotal += lineItem.Price; } // Subtract Discounts for (int discount : Discounts) subTotal -= discount; // Calculate Tax int tax = subTotal * Tax; // Calculate GrandTotal int grandTotal = subTotal + tax; return grandTotal; } }

咋看,代码并没有什么大的问题,order中定义了很多关于自身的属性,还有对属性的一些业务操作,但是,计算价格,其实并不是order对象本身应该关系的。因此,需要引入一个计算order price能力的类

public class Order1    {        private List
OrderLineItems ; private List
Discounts; private int Tax ; public int Calculate(){ return new OrderCalculator(this).Calculate(); } } public class OrderCalculator{ private Order1 order; private List
OrderLineItems ; private List
Discounts; private int Tax ; public OrderCalculator(Order1 order){ this.order=order; } public int Calculate() { int subTotal = 0; // Total up line items for (OrderLineItem lineItem : OrderLineItems) { subTotal += lineItem.Price; } // Subtract Discounts for (int discount : Discounts) subTotal -= discount; // Calculate Tax int tax = subTotal * Tax; // Calculate GrandTotal int grandTotal = subTotal + tax; return grandTotal; } }

14.单一责任

上面的问题,其实一直提到设计原则,自然也提到了单一责任原则SRP,要学重构,SRP是必然要知道,且学会的思想,并且灵活应用到重构代码中。

下面作者举了一个Video的例子,Video类中有两个方法,分别负责统计客户购买的Video数量,并且计算每个客户的购买金额

public class Video    {        public void PayFee(int fee)        {        }        public void RentVideo(Video video, Customer customer)        {            customer.Videos.add(video);        }        public int CalculateBalance(Customer customer)        {            return customer.LateFees.size();        }    }    public class Customer    {        public List
LateFees; public List

很明显,顾客购买Video的金额,并不是Video本身应该关系的,而是每个Customer应该关系的,因此,需要将计算购买金额的方法下移到Customer类中来完成

public class Video1    {        public void RentVideo(Video1 video, Customer1 customer)        {            customer.Videos.add(video);        }    }    public class Customer1    {        public List
LateFees; public List
Videos ; public void PayFee(int fee) { } public int CalculateBalance(Customer1 customer) { return customer.LateFees.size(); } }

15.移除拷贝

当我们有两段一样的代码的时候,很明显,我们需要对他进行简单的封装(具体如何处理,这里先不说,技巧很多种),让重复的代码彻底消息掉。这个可能也是重构最简单,也是最好用的一种方式了

public class MedicalRecord    {        public Date DateArchived ;        public boolean Archived;        public void ArchiveRecord()        {            Archived = true;            DateArchived = new Date();        }        public void CloseRecord()        {            Archived = true;            DateArchived = new Date();        }    }

我们模拟了一段在两个方法中都存在相同逻辑的代码,这时候,我们就要对他进行重构了

public class MedicalRecord1    {        public Date DateArchived ;        public boolean Archived;        public void ArchiveRecord()        {            init();        }        public void CloseRecord()        {            init();        }        public void init()        {            Archived = true;            DateArchived = new Date();        }    }

16.封装条件

简单来说,就是对复杂的条件逻辑判断,进行单独处理,这样,当条件参数发生变化的时候,不会影响到真实的业务逻辑流程

public class RemoteControl {        private String[] Functions;        private String Name;        private int CreatedYear;        public String PerformCoolFunction(String buttonPressed) {            // Determine if we are controlling some extra function            // that requires special conditions            if (Functions.length > 1 && Name == "RCA" && CreatedYear > new Date().getYear() - 2) {                return "doSomething";            }            return "";        }    }

如何处理呢

public class RemoteControl2 {        private String[] Functions;        private String Name;        private int CreatedYear;        public String PerformCoolFunction(String buttonPressed) {            // Determine if we are controlling some extra function            // that requires special conditions            if (HasExtraFunctions()) {                return "doSomething";            }            return "";        }        private boolean HasExtraFunctions()        {           return Functions.length > 1 && Name == "RCA" && CreatedYear > new Date().getYear() - 2 ;        }    }

17.提取父类

如何理解呢?简单来说,就是当我们发现定义的方法,可以被抽象成更高层次对象的时候,就需要考虑抽象一个更上层的父类,并将接口迁移到父类中去定义

public class Dog    {        public void EatFood()        {            // eat some food        }        public void Groom()        {            // perform grooming        }    }

重构后的效果

public class Animal    {        public void EatFood()        {            // eat some food        }        public void Groom()        {            // perform grooming        }    }    public class Dog1 extends Animal    {    }

但是需要注意,过多的继承容易引起耦合,所以有时候,我们需要考虑接口或则聚合来解决继承带来的强依赖。

18.条件判断代替异常

这个其实在很多语言规则中,都有提到,就是不能使用异常来代替控制逻辑,比如《effective java》一书中就有提到。

public class Microwave    {        public boolean Start()        {            boolean foodCooked = false;            try            {                //do something perhaps throw new exception                foodCooked = true;            }            catch (Exception e)            {                foodCooked = false;            }            return foodCooked;        }    }}

重构后的效果

public class Microwave1    {        public boolean Start()        {            boolean foodCooked = false;               //mock 模拟先判断是否满足某种条件,避免异常发生                if(true){                    //do something                    foodCooked = true;                }else {                    foodCooked = false;                }            return foodCooked;        }    }

19.拓展工厂类

将创建对象的过程给封装起来,这就是工厂模式的设计初衷。将一些列有关系的产品簇组合成一个最终的产品,便是抽象工厂了。好像讲偏了,回归正题,使用工厂模式,从重构角度来看,就是为了实现单一职责,使得

代码更加稳定。

public class PoliceCarController    {        public PoliceCar New(int mileage, boolean serviceRequired)        {            PoliceCar policeCar = new PoliceCar();            policeCar.ServiceRequired = serviceRequired;            policeCar.Mileage = mileage;            return policeCar;        }    }        class PoliceCar{                public boolean ServiceRequired;        public int Mileage;    }

重构后的效果

public interface IPoliceCarFactory    {        PoliceCar Create(int mileage, boolean serviceRequired);    }    public class PoliceCarFactory implements IPoliceCarFactory    {        public PoliceCar Create(int mileage, boolean serviceRequired)        {            PoliceCar policeCar = new PoliceCar();            policeCar.ServiceRequired = serviceRequired;            policeCar.Mileage = mileage;            return policeCar;        }    }    public class PoliceCarController1    {        public IPoliceCarFactory PoliceCarFactory ;        public PoliceCarController1(IPoliceCarFactory policeCarFactory)        {            PoliceCarFactory = policeCarFactory;        }        public PoliceCar New(int mileage, boolean serviceRequired)        {            return PoliceCarFactory.Create(mileage, serviceRequired);        }    }

20.提取子类

这个方式,之前好像已经提到的下移方法类似,也是为了遵循接口隔离原则。

public interface Ball    {        public void play();        public void size();        //打气        public void pumpUp();    }

球,可以用来玩,也都有他们的大小,但是不是每种球,都需要打球的pumpUp

因此需要将pumpUp方法下移到具体子类中

public interface BasketBall extends   Ball2{        //打气        public void pumpUp();    }    public interface Ball2    {        public void play();        public void size();    }

21合并集成

//将子类的方法迁移到父类中 不多说了,我想静静

public abstract class Website    {        public abstract String Title();    }    public abstract  class StudentWebsite extends Website    {        public abstract boolean IsActive() ;    }

改造后的结构

public abstract class Website2    {        public abstract String Title();        public abstract boolean IsActive() ;    }    public abstract  class StudentWebsite2 extends Website    {           }

虽然感觉跟上移方法很像,但是确实在职责区分中,一定需要判断好,方法到底归属于父类还是子类。

22.分解方法

是不是想到了"提取方法"了,omg。果然够2,我只贴代码,不说话 orz

public class CashRegister    {        public CashRegister()        {            Tax = 0.06f;        }        private float Tax ;        public void AcceptPayment(Customer customer, List
products, int payment) { float subTotal = 0f; for (Product product : products) { subTotal += product.Price; } for (Product product : products) { subTotal -= product.AvailableDiscounts; } float grandTotal = subTotal * Tax; customer.DeductFromAccountBalance(grandTotal); } } public class Customer { public void DeductFromAccountBalance(float amount) { // deduct from balance } } public class Product { public int Price ; public int AvailableDiscounts ; }

方法封装后的结构

public class CashRegister2    {        public CashRegister2()        {            Tax = 0.06f;        }        private float Tax ;        private List
Products; public void AcceptPayment(Customer customer, List
products, int payment) { int subTotal = CalculateSubtotal(); subTotal = SubtractDiscounts(subTotal); float grandTotal = AddTax(subTotal); SubtractFromCustomerBalance(customer, grandTotal); } private void SubtractFromCustomerBalance(Customer customer, float grandTotal) { customer.DeductFromAccountBalance(grandTotal); } private float AddTax(int subTotal) { return subTotal * Tax; } private int SubtractDiscounts(int subTotal) { for (Product product : Products) { subTotal -= product.AvailableDiscounts; } return subTotal; } private int CalculateSubtotal() { int subTotal = 0; for (Product product : Products) { subTotal += product.Price; } return subTotal; } }

23.引入参数对象

此重构模式非常的好用,也非常容易上手,重点推荐,下面代码中,可以比较下

public void test(boolean check, String str, int order) {        //todo    }    public void test(Argument argument) {        //todo    }    class Argument {        boolean check;        String str;        int order;    }

24.分解复杂判断

原意是移除箭头模式,简言之,即对于复杂的逻辑判断if else{if else ..}类似这样嵌套判断,可以有一些重构的技巧

public class Security    {        public List list;        public Security(List list)        {            this.list = list;        }        public boolean HasAccess(Date date, String []arrs, List
exemptions) { boolean hasPermission = false; if (date != null) { if (arrs != null) { if (arrs.length == 0) { if (null!=exemptions&&exemptions.get(0).equals("abc")) { hasPermission = true; } } } } return hasPermission; } }

如何重构呢,比较通用的一个做法是判断一次,return一次

public boolean HasAccess2(Date date, String[] arrs, List
exemptions) { boolean hasPermission = false; if (date == null||arrs==null) { return false; } if(arrs.length!=0){ return false; } if (null != exemptions && exemptions.get(0).equals("abc")) { return true; } return false; }

最后是stackoverflow上,关于arrowhead pattern的一些建议:http://stackoverflow.com/questions/17804005/how-to-prevent-the-arrowhead-anti-pattern/17813388

25.引入契约检查

Design by contract,即要求我们对输入和输出都进行验证,已保证系统不会因为意想不到的情况出现,而导致程序出现不可以控的情况

先看下面的例子

public class CashRegister    {        public int TotalOrder(List
products, Calendar calendar) { int orderTotal =products.size(); orderTotal+=calendar.get(Calendar.SUNDAY); return orderTotal; } }

采用DBC后的重构效果

public int TotalOrder2(List
products, Calendar calendar) { if (products == null) { throw new NullPointerException("products must not be empty"); } if (products.size() == 0) { throw new ArithmeticException("products's size must more than one"); } //calendar校验省略 int orderTotal = products.size(); orderTotal += calendar.get(Calendar.SUNDAY); //输出校验 if (orderTotal == 0) { throw new SecurityException("orderTotal's value must bigger than 0"); } return orderTotal; }

更多关于DBC:https://en.wikipedia.org/wiki/Design_by_contract

26.避免双重否定

没什么好说的,直接上代码吧。

/** * @title 避免双重否定 * @desc * @atuh lwx * @createtime on 2015/11/14 16:27 */public class Day_26 {      static boolean isEmpty(String str){        if(null==str||str.length()==0){            return true;        }        return false;    }      static boolean isNotEmpty(String str){        return !isEmpty(str);    }    public static void main(String[] args) {        if(!isEmpty("")){            //todo        }        //        if(isNotEmpty("")){                                }    }}

27.移除上帝类

如何理解所谓的上帝类呢,说白了,就是一些“功能强大的工具/管理类”,他可能庞大到整个业务系统只会有一个的工具类,这样就违反了单一责任原则。

public class CustomerService {        public int CalculateOrderDiscount(String str) {            // do work            return 0;        }        public boolean CustomerIsValid(String str) {            // do work            return true;        }        public List
GatherOrderErrors() { // do work return null; } public void Register(Object customer) { // do work } public void ForgotPassword(Object customer) { // do work } }

职责明确后的结构

public class CustomerService2 {        public int CalculateOrderDiscount(String str) {            // do work            return 0;        }        public boolean CustomerIsValid(String str) {            // do work            return true;        }        public List
GatherOrderErrors() { // do work return null; } } public class CustomerRegistrationService{ public void Register(Object customer) { // do work } public void ForgotPassword(Object customer) { // do work } }

28.重命名布尔类型方法

如果有Boolean类型参数,则为了简化外部调用带来的困难,一般会使用重命名方法来简化调用带来的困难,当然,也可以通过重载来弱化boolean变量在使用中带来的不变

public class BankAccount    {        public void CreateAccount( Object customer,boolean withChecking, boolean withSavings)        {            // do work        }    }

改造后的结果

public class BankAccount2    {        public void CreateAccountWithChecking(Object customer)        {            CreateAccount(customer, true, false);        }        public void CreateAccountWithCheckingAndSavings(Object customer)        {            CreateAccount(customer, true, true);        }        private void CreateAccount(Object customer, boolean withChecking, boolean withSavings)        {            // do work        }    }

29.去除中间人

如何理解去除中间人呢?简单理解,就是当A需要通过B去访问C的时候,并且B除了调用C的方法,不在有任何作用的时候,则B就成了所谓的中间人,就应该被delete掉

public class Consumer {        public AccountManager AccountManager;        public Consumer(AccountManager accountManager) {            AccountManager = accountManager;        }        public void Get(int id) {            Account account = AccountManager.GetAccount(id);        }    }    public class AccountManager {        public AccountDataProvider DataProvider;        public AccountManager(AccountDataProvider dataProvider) {            DataProvider = dataProvider;        }        public Account GetAccount(int id) {            return DataProvider.GetAccount(id);        }    }    public class AccountDataProvider {        public Account GetAccount(int id) {            // get account            return null;        }    }    class Account {    }

重构后的效果

public class Consumer2    {        public AccountDataProvider AccountDataProvider ;        public Consumer2(AccountDataProvider dataProvider)        {            AccountDataProvider = dataProvider;        }        public void Get(int id)        {            Account account = AccountDataProvider.GetAccount(id);        }    }

这里需要作两点补充:第一,AccountManager当初设计是为了隔离Consumer与AccountProvider,后面可能随着业务形态发生变化,两者可以直接调用的时候,AccountManager对象就失去了意义。

举个简单的例子,我们买电视,都是去超市去买,因为你不可能直接去厂家拿货,如果哪天你的角色变成代理商或则厂家工人了,也许,你就可以内部直接拿货了

第二,有时候,对于两个需要隔离的对象,需要制造一个中间人,来隔离他们。好比,你原先是公司的员工,享受福利,离职后,就不会再有这种福利了。内部的一些东西,你也就接触不到了。

30.尽快返回

return as soon as possible。即对之前的复杂逻辑判断的一个侧面说明了。

public class Order {        public Object Customer;        public int CalculateOrder(Object customer, List products, int discounts) {            Customer = customer;            int orderTotal = 0;            if (products.size() > 0) {                orderTotal = products.size();                if (discounts > 0) {                    orderTotal -= discounts;                }            }            return orderTotal;        }    }

改造后

public class Order2 {        public Object Customer;        public int CalculateOrder(Object customer, List products, int discounts) {            Customer = customer;            int orderTotal = 0;            if (products.size() == 0) {                return 0;            }            orderTotal = products.size();            if (discounts > 0) {                orderTotal -= discounts;            }            return orderTotal;        }    }

31.使用多态代替条件

上面其实也提到了策略模式替换多条件,其实是类似的。如果对java的单双派机制,有更多了解的,可以移步我之前写的一篇文章,

/** * @title 使用多态代替条件判断 * @desc * @atuh lwx * @createtime on 2015/11/14 17:41 */public class Day_31 {    public static void main(String[] args) {        Day_31 day_31 = new Day_31();        Parent parent = new Parent();        Son son = new Son();        Daughter daughter = new Daughter();        day_31.invokeSay(parent);        day_31.invokeSay(son);        day_31.invokeSay(daughter);        System.out.println("华丽的分割线");        //使用动态方式        day_31.invokeSay2(parent);        day_31.invokeSay2(son);        day_31.invokeSay2(daughter);        //考虑重载解决 -->又涉及到单分派-->通过使用访问者模式来解决    }    public void invokeSay(Object parent) {        if (parent instanceof Son) {            ((Son) parent).say();        } else if (parent instanceof Daughter) {            ((Daughter) parent).say();        } else {            ((Parent)parent).say();        }    }    public void invokeSay2(Parent parent) {            parent.say();    }}class Parent {    public void say() {        System.out.println("parent say");    }}class Son extends Parent {    public void say() {        System.out.println("Son say");    }}class Daughter extends Parent {    public void say() {        System.out.println("Daughter say");    }}

 

你可能感兴趣的文章
http2-head compression
查看>>
C# 命名空间
查看>>
订餐系统之同步美团商家订单
查看>>
使用ArrayList时设置初始容量的重要性
查看>>
Java Web-----JSP与Servlet(一)
查看>>
Maven搭建SpringMVC+Mybatis项目详解
查看>>
关于量子理论:最初无意的简化,和一些人有意的强化和放大
查看>>
CentOS 6.9通过RPM安装EPEL源(http://dl.fedoraproject.org)
查看>>
“区块链”并没有什么特别之处
查看>>
没有功能需求设计文档?对不起,拒绝开发!
查看>>
4星|《先发影响力》:影响与反影响相关的有趣的心理学研究综述
查看>>
IE8调用window.open导出EXCEL文件题目
查看>>
python之 列表常用方法
查看>>
vue-cli脚手架的搭建
查看>>
在网页中加入百度搜索框实例代码
查看>>
在Flex中动态设置icon属性
查看>>
采集音频和摄像头视频并实时H264编码及AAC编码
查看>>
3星|《三联生活周刊》2017年39期:英国皇家助产士学会于2017年5月悄悄修改了政策,不再鼓励孕妇自然分娩了...
查看>>
高级Linux工程师常用软件清单
查看>>
堆排序算法
查看>>