其實不少模式,咱們平時就已經用到,只是不知道而已。html
1.集合的封裝java
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<String> list = day1Test.getList(); //肆無忌憚的操做 list.add("a"); day1Test.iterator(); //正確的作法 Day1Test2 day1Test2 = new Day1Test2(); //獲取到了內部對象 List<String> list2 = day1Test2.getList(); //肆無忌憚的操做 list2.add("a"); day1Test2.iterator(); } static class Day1Test { private List<String> list = new ArrayList<String>(); 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<String> list = new ArrayList<String>(); 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); } } } }
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.提高方法ide
簡單點說,若是子類都有相同的方法,那就應該將方法提上到父類層函數
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 { }
與第三個上升方法相比,有時候,父類的方法,隨着業務的變化,只適合部分子類的時候,則須要將父類的方法下移到具體須要的子類中,這樣才符合接口最小原則^^單元測試
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 { }
同提高方法,思路同樣的,就很少說了ui
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 { }
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 { }
demo就不上,只提一點,命名規則不要擔憂太長,而選擇簡寫,這樣反而爲後期的維護帶來麻煩。
設計模式中,不少模式就使用了委託的方式,來解耦繼承帶來的強依賴,好比裝飾者,適配器模式等等。
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暴露出來,就是裝飾者了。
官方已經找不到這個頁面的連接了,參考了其餘地方,作法其實也很簡單,就是遵循了接口最小原則來設計的
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(); }
提取方法是重構中很常見到的一種手法。他能夠經過方法名,增長代碼的可讀性,減小沒必要要的註釋說明。
class Receipt { private List<Float> discounts; private List<Float> 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<Float> discounts; private List<Float> itemTotals; public float CalculateGrandTotal() { float subTotal = 0f; subTotal=addItemTotals(itemTotals); subTotal=minuteDiscounts(itemTotals); subTotal=calcTax(subTotal); return subTotal; } float addItemTotals(List<Float> itemTotals){ float subTotal = 0f; for (Float itemTotal : itemTotals) { subTotal += itemTotal; } return subTotal; } float minuteDiscounts(List<Float> 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; } }
其實就是用多態減小 if-else-if,是一個值得記住的方法,但要注意抽出總體的邏輯。
不少時候,要完成目標的方式不是隻有一種,當咱們須要使用不一樣的條件,來獲取不一樣的結果的時候,咱們可使用策略模式,這樣,不會由於新增長一個條件,而去修改判斷邏輯
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<State,CalculateShippingAmountStrategy>strategyFactory=new HashMap<State, CalculateShippingAmountStrategy>(); 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; } }
其實就是依賴的變量,儘可能用虛擬類和接口,減小對具體類的依賴。這很重要,有助於理解平時開發的框架。不過變化不大的需求不必用這個。
六大設計原則中的最少知識原則(迪米特)說的就是,對依賴的瞭解,下降到最少。做者強調,當咱們進行單元測試的時候,咱們就須要必定的隔離,不然沒法進行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(); } }
這並非一種很常見的重構手段,即當咱們對象中定義了不少變量,及其須要利用這些變量進行一些業務操做的時候,能夠考慮將方法提取到一個新的類中,這樣就解耦了變量與邏輯操做的直接關聯。
也比較符合單一責任原則。
public class OrderLineItem { public int Price ; } public class Order { private List<OrderLineItem> OrderLineItems ; private List<Integer> 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<OrderLineItem> OrderLineItems ; private List<Integer> Discounts; private int Tax ; public int Calculate(){ return new OrderCalculator(this).Calculate(); } } public class OrderCalculator{ private Order1 order; private List<OrderLineItem> OrderLineItems ; private List<Integer> 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; } }
上面的問題,其實一直提到設計原則,天然也提到了單一責任原則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<Integer> LateFees; public List<Video> Videos ; }
很明顯,顧客購買Video的金額,並非Video自己應該關係的,而是每一個Customer應該關係的,所以,須要將計算購買金額的方法下移到Customer類中來完成
public class Video1 { public void RentVideo(Video1 video, Customer1 customer) { customer.Videos.add(video); } } public class Customer1 { public List<Integer> LateFees; public List<Video1> Videos ; public void PayFee(int fee) { } public int CalculateBalance(Customer1 customer) { return customer.LateFees.size(); } }
其實就是去除重複代碼
當咱們有兩段同樣的代碼的時候,很明顯,咱們須要對他進行簡單的封裝(具體如何處理,這裏先不說,技巧不少種),讓重複的代碼完全消息掉。這個可能也是重構最簡單,也是最好用的一種方式了
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(); } }
簡單來講,就是對複雜的條件邏輯判斷,進行單獨處理,這樣,當條件參數發生變化的時候,不會影響到真實的業務邏輯流程
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 ; } }
如何理解呢?簡單來講,就是當咱們發現定義的方法,能夠被抽象成更高層次對象的時候,就須要考慮抽象一個更上層的父類,並將接口遷移到父類中去定義
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 { }
可是須要注意,過多的繼承容易引發耦合,因此有時候,咱們須要考慮接口或則聚合來解決繼承帶來的強依賴。
這個其實在不少語言規則中,都有提到,就是不能使用異常來代替控制邏輯,好比《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; } }
將建立對象的過程給封裝起來,這就是工廠模式的設計初衷。將一些列有關係的產品簇組合成一個最終的產品,即是抽象工廠了。好像講偏了,迴歸正題,使用工廠模式,從重構角度來看,就是爲了實現單一職責,使得
代碼更加穩定。
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); } }
這個方式,以前好像已經提到的下移方法相似,也是爲了遵循接口隔離原則。
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(); }
//將子類的方法遷移到父類中 很少說了,我想靜靜
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 { }
雖然感受跟上移方法很像,可是確實在職責區分中,必定須要判斷好,方法到底歸屬於父類仍是子類。
是否是想到了"提取方法"了,omg。果真夠2,我只貼代碼,不說話 orz
public class CashRegister { public CashRegister() { Tax = 0.06f; } private float Tax ; public void AcceptPayment(Customer customer, List<Product> 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<Product> Products; public void AcceptPayment(Customer customer, List<Product> 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; } }
此重構模式很是的好用,也很是容易上手,重點推薦,下面代碼中,能夠比較下
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 ..}相似這樣嵌套判斷,能夠有一些重構的技巧
去除 if-else 重複嵌套,通用的一個作法是判斷一次,return一次,很是有用。
public class Security { public List list; public Security(List list) { this.list = list; } public boolean HasAccess(Date date, String []arrs, List<String> 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<String> 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
其實平時開發都要這樣作,很是有用。
Design by contract,即要求咱們對輸入和輸出都進行驗證,已保證系統不會由於意想不到的狀況出現,而致使程序出現不能夠控的狀況
先看下面的例子
public class CashRegister { public int TotalOrder(List<String> products, Calendar calendar) { int orderTotal =products.size(); orderTotal+=calendar.get(Calendar.SUNDAY); return orderTotal; } }
採用DBC後的重構效果
public int TotalOrder2(List<String> 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
沒什麼好說的,直接上代碼吧。
/** * @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("")){ } } }
如何理解所謂的上帝類呢,說白了,就是一些「功能強大的工具/管理類」,他可能龐大到整個業務系統只會有一個的工具類,這樣就違反了單一責任原則。
public class CustomerService { public int CalculateOrderDiscount(String str) { // do work return 0; } public boolean CustomerIsValid(String str) { // do work return true; } public List<String> 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<String> GatherOrderErrors() { // do work return null; } } public class CustomerRegistrationService{ public void Register(Object customer) { // do work } public void ForgotPassword(Object customer) { // do work } }
若是有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 } }
如何理解去除中間人呢?簡單理解,就是當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對象就失去了意義。
舉個簡單的例子,咱們買電視,都是去超市去買,由於你不可能直接去廠家拿貨,若是哪天你的角色變成代理商或則廠家工人了,也許,你就能夠內部直接拿貨了
第二,有時候,對於兩個須要隔離的對象,須要製造一箇中間人,來隔離他們。比如,你原先是公司的員工,享受福利,離職後,就不會再有這種福利了。內部的一些東西,你也就接觸不到了。
return as soon as possible。即對以前的複雜邏輯判斷的一個側面說明了。
public class Order { public Object Customer; public int CalculateOrder(Object customer, List<Object> 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<Object> products, int discounts) { Customer = customer; int orderTotal = 0; if (products.size() == 0) { return 0; } orderTotal = products.size(); if (discounts > 0) { orderTotal -= discounts; } return orderTotal; } }
上面其實也提到了策略模式替換多條件,實際上是相似的。若是對java的單雙派機制,有更多瞭解的,能夠移步我以前寫的一篇文章,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"); } }