《K的技術學習筆記》——良好OOP的設計原則:<SOLID Principles>(三)
開閉原則(Open–closed principle)
開放去被繼承,封閉去被改動。詳細說明就是這些已完成的class或function可以自由被使用或是擴展用途,但不可以直接修改,增加或減少當中的結構或是邏輯。
舉一個單車例子。
現在有一輛單車A(Bicycle),他要去公路A(Road)再到公路B(Road)
單車(Bicycle)
單車會有他的最高速度(maxSpeed), 現在速度(speed), 加減速時的間隔(speedInterval)和現在的位置(location)。
單車可以加速(speedUp), 減速(slowDown), 去不同地方(goTo)和被讀取現在位置(getLocation)
公路(Road)
公路會有最高限速(limtMaxSpeed), 最低限速(limtMinSpeed)和公路上行走的單車(bicycles)
他可以讓單車進來(addBicycle), 離去(removeBicycle)或是找出不在限速範圍內的單車驅趕出去(findAndRemoveIllegalBicycles)。
世界(world)
他就是運行程式的地方。我們要運行的內容就在running()裡。我們先在世界裡創造兩個公路, 分別是公路A(roadA)和公路B(roadB)。最後, 就是單車A(bicycleA)。
單車A先去到公路A再加速10次。
之後, 公路A就尋找有沒有不在限速範圍內的單車。
因為單車A的速度在正常限速裡, 所以沒有受到影響。
然後, 離開公路A去公路B再減速5次。
之後, 公路B就尋找有沒有不在限速範圍內的單車。
因為單車A的速度在正常限速裡, 所以沒有受到影響。
最後, 就讀取單車A的位置確認是在公路B上。
若果現在被要求單車的加減速時的間隔(speedInterval)改為15, 我們就回到單車的class修改。但我們忘記了原來的加速(speedUp)和減速(slowDown)的邏輯是以加減速時的間隔為10作為前題來寫。我們忘了修改加速(speedUp)和減速(slowDown)。這就出問題了。單車A的現在速度(speed)可以大於最高速度(maxSpeed)。加速10次後, 單車A的現在速度(speed)是105。這速度完全超出了公路A的限速。因此, 被驅趕出去, 而去不了公路B。
這裡其實想帶出的點是每進行修改一個很多地方用了的class和function, 出現預想之外的bug機會就更多。
哪我們若果要遵守開閉原則(Open–closed principle)要怎麼做, 以下就是例子:
單車介面(Bicycle)
我們使用介面規定下單車應該有什麼特性和能做什麼, 但當中的邏輯就在往後創造一個class時實作。
普通單車(NormalBicycle)
這個和上面的單車class是一樣的, 他就是實作了單車介面。
變速器介面(GearBox)
這個介面要求變速器有不同的擋(gears)和換擋(shiftGear)
可變速單車(ChangeGearBicycle)
這個單車繼承了普通單車的功能和要求實作變速器的特性。因為普通單車的加減速邏輯是以加減速時的間隔為10作前題,所以我們要覆寫加減速的邏輯。這裡覆寫為用了原來的邏輯再做檢查。若大於最高速, 就設為最高速。若小於0, 就設為0。這樣不會改動了普通單車裡的內容, 而我們還能創造我要用的新class。
世界(world)
這個世界的單車B就像是上個世界的單車A, 而這裡的單車A就是新的可變速單車, 並換擋加減速間隔(speedInterval)為15。他們運行的內容和上個世界都是一樣的, 但這世界的單車A並沒有在加速10次後, 超速公路A的限速, 所以照樣能到公路B。
總結
若果class或function已被不同地方使用後再作出改動, 不能預測的bug就會出現很多。遵守開閉原則(Open–closed principle)就能大大減少這問題。雖然是這麼說,但現實是很難做到的,只有我們從一開始知道所有資料,才能百分百做到。因此,在現實中就盡量不要去做改動,但真的不改動會做成日後維護困難,還是可以改動的。