點擊上方[全棧開發者社區]→右上角[...]→[設為星標⭐]
讀牛人技術博客 A Java Geek,最開始覺得這樣的想法很有創意。提前使用靜態代碼塊把對象存入map容器中,在需要的時候在取。他也有提到可以使用DI的方式把需要的對象提前注入好,但是這兩種方式都會造成內存的浪費,因為有一些對象可能是頻繁使用,而有些對象用的概率小甚至一次都沒有用到,那麼這樣的方式是不好的。而且,我們是去除if…else…的語句,這樣的方式雖然好像沒有了if…else…語句,但是本質上並不是最好的方式,只是提供了一種思維方式。
讀《重構 改善既有代碼的設計》有一條就是,以多態取代條件表達式。這是才是最本質的解決方式。
這裡的去除if…else…語句,不是遇見了if…else…語句就去除。這裡是這樣描述的:你手上有個條件表達式,它根據對象類型的不同而選擇不同的行為。而不是平時編寫代碼遇見一些普通的條件表達式就去把它去除,不是這樣的。
而且,一般來說程式語言都有switch語句去替代if…esle…語句。從性能上看這兩個語法也只有非常細微的差別,根本無需關心自己使用了哪個語法。
以多態取代條件表達式代碼的壞味道一:
double getSpeed() { switch_ (_type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts; case NORWEGIAN_BLUE: return (is_Nailed) ? 0 : getBaseSpeed(_voltage); } throw new RuntimeException("Should be unreachable");}代碼的壞味道二:
public Foo getFoo(Bar bar) {
if (bar instanceof BarA) { return new FooA(); } else if (bar instanceof BarB) { return new FooB(); } else if (bar instanceof BarC) { return new FooC(); } else if (bar instanceof BarD) { return new FooD(); } throw new BarNotFoundException();}思路
將這個條件表達式的每個分支放進一個子類內的覆寫函數中,然後將原始函數聲明位抽象函數。
動機(為什麼我們要使用多態取代條件表達式?)
多態最根本的好處就是:如果你需要根據對象的不同類型而採取不同的行為,多態使你不必編寫明顯的條件表達式。
類圖
根據代碼的壞味道一和二以及類圖關係,我們可以得到一個初始版本的代碼
Employee
class Employee... 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"); } } int getType() { return _type.getTypeCode(); } private EmployeeType _type;EmployeeType
abstract class EmployeeType... abstract int getTypeCode();Engineer
class Engineer extends EmployeeType... int getTypeCode() { return Employee.ENGINEER; }Manager
class Manager extends EmployeeType... int getTypeCode() { return Employee.MANAGER; }Salesman
class Salesman extends EmployeeType... int getTypeCode() { return Employee.SALESMAN; }最終結果代碼布局
Employeeclass Employee... int payAmount() { return _type.payAmount(this); } private EmployeeType _type;EmployeeType
class EmployeeType... abstract int payAmount(Employee emp);Engineer
class Engineer extends EmployeeType... int payAmount(Employee emp) { return emp.getMonthlySalary(); }Manager
calss Manager extends EmployeeType... int payAmount(Employee emp) { return emp.getMonthlySalary() + emp.getBouns(); }Salseman
class Salseman extends EmployeeType... int payAmount(Employee emp) { return emp.getMonthlySalary() + emp.getCommission(); }理解
a, 把Employee中的原來的屬性_monthlySalary,_commission,_bonus變成最終的採用一個函數獲取。
b, 注意的地方就是誰組合了誰。這裡就是Employee組合了EmployeeType。或者可以理解為誰持有了誰的引用。
c, 其次就是一個繼承關係。
小結
由於偶然讀到別人技術博客關於if…else…的取代文章,發現這也是一個思路,但是不夠那麼好,於是記錄下《重構 改善既有代碼設計》的一個以多態取代條件表達式的範例。
雖然這樣確實處理了if…else…語句,但是一旦使用多態取代條件表達式的方式,必定會引入一個繼承或者實現體系,其實,這是增加了理解的複雜度。
面向對象的編程,如果增加了擴展性必定會引入設計模式,而一旦引入設計模式必定增加理解的複雜度,因為總有繼承體系和實現體系結構,這種結構也是面向對象編程的特色。面向對象編程不一定比面向過程好。在實際的編碼過程中,還是需要權衡這兩種方式。
參與留言集贊送書活動:一個合格的技術面試官是怎麼樣的?(文末送書)
留言打卡27天。
覺得本文對你有幫助?請分享給更多人
關注「全棧開發者社區」加星標,提升全棧技能
本公眾號會不定期給大家發福利,包括送書、學習資源等,敬請期待吧!
如果感覺推送內容不錯,不妨右下角點個在看轉發朋友圈或收藏,感謝支持。
好文章,我在看❤️