Code Style Guide之正交设计浅析
前提:模塊化設計
為什么需要模塊化設計?
理論上可以只使用一個函數完成全部功能,但是太過復雜,超過人的掌控極限。因此必須要劃分開,對問題進行分解。(面向過程->面向對象)
模塊化設計遇到的兩個問題
- 如何劃分模塊?
- 模塊之間如何連接?
軟件設計
為何要做軟件設計?
軟件設計是為了讓軟件在長期范圍內容易應對變化。即:盡量降低變化對軟件的影響。否則維護成本太大。
HOW?
高內聚、低耦合原則
- 內聚:一個單位內部事物之間關聯的緊密程度。
- 高內聚:將同類事物放在一起,只做一件事(單一職責)。
- 耦合:不同單位之間關聯的緊密程度。
- 低耦合:不同單位之間盡量不要互相影響。
什么是好的模塊化設計?
模塊本身高內聚,不同模塊間低耦合。
正交
什么是正交?
- 二維空間:兩條直線正交、正交分解
- 多維空間:向量正交
- 特點:正交的兩個單位互不影響。
模塊化設計 & 正交設計
- 模塊之間互不影響(正交)
- 模塊的劃分實際上是功能職責的劃分(如何劃分模塊)
- 每個模塊保證自己功能的實現,不關心其他模塊如何實現
- 模塊之間聯系的橋梁是接口(API),接口是模塊之間的分界線(模塊之間如何連接)
通俗的說,只要接口不變,一個模塊對另一個模塊的影響就是0,無論提供接口的模塊內部實現如何變動,對調用接口的模塊來說都是透明的。
舉例:
例1:
1. 模塊A負責排序,提供接口sort
2. 模塊B在功能實現邏輯中需要得到排好序的數據,調用了模塊A的sort接口,實現了自身的功能
- 模塊A不關心誰來調用sort接口,不論是模塊B還是模塊C。外部的變動對模塊自身無影響。
- 模塊B只需要知道調用模塊A的sort接口可以對數據進行排序,而不關心模塊A內部使用了什么排序算法。即使有一天模塊A的排序算法從冒泡排序變成了歸并排序,模塊B的實現代碼也不需要有任何改動。
例2:設計一個結賬計算器
public Class Goods {private double price;public double getPrice() {return price;}public void setPrice(double price) {this.price = price;} }設計的問題:不應當把物品自己的算賬細節與購物車的算賬細節放到一起,模塊之間耦合度太高。
四個策略
策略一:消除重復
重復的代碼意味著相同的事物沒有被放到一起,即低內聚。
舉例:有多個地方都需要對數據排序,應當寫一個工具類進行數據排序,而不是在每個地方自己寫重復的排序代碼。
有重復的代碼意味著違反單一職責原則,他們做了不止一件事。
所以,每當發現自己在寫重復的代碼時,應當將重復的部分剝離出來。
策略二:分離不同的變化方向
如果總是因為一些類似的原因修改模塊內同一部分代碼,而其他部分的代碼不變,則應該將變化的方向抽離出來。
舉例:一件商品有時候打五折,有時候打九折,有時候不打折,那么就應當將折扣抽離出來,為商品增加“折扣”這個屬性。
策略三:縮小依賴范圍
兩個模塊之間依靠API進行關聯,因此API決定了模塊間的耦合度。
API設計的要點:
1. API應包含盡量少的知識,因為任何一項知識的變化都會導致雙方的變化;
2. API也應該高內聚,而不應該強迫API的調用者依賴它不需要的東西。
舉例:
public interface Saleable {double checkout(); }public abstract Class Goods implements Saleable {private double price;//getter setter...@Overridepublic double checkout() {...} }public Class GoodsA {... }public double checkout (List<Goods> shoppingGoods) {double sum = 0d;for (Goods good : shoppingGoods) {sum += good.checkout();}return sum; }對于checkout方法來說,聲明了傳入的參數類型是List<Goods>,但是在方法內部只調用了good.checkout()方法,而這個方法實際上是Saleable接口所聲明的。因此,這個函數的聲明應當是:
public double checkout (List<Saleable> saleableList) {double sum = 0d;for (Saleable saleable : saleableList) {sum += saleable.checkout();}return sum; }之前的設計中,API包含了多余的知識,要求參數必須是List<Goods>,然而在實現細節中沒有用到Goods類的任何東西,它強迫這個API的調用者必須傳入List<Goods>類型的參數。然而實際上,如果有另一個實現了Saleable接口但沒有繼承Goods類的類,那么這個類是無法使用這個API的,即API的內聚程度不夠高,它強迫API的調用者依賴它不需要的東西。
策略四:向著穩定的方向依賴
兩個模塊之間如果有API的調用關系,那么這兩個模塊必然有一定程度的耦合。因此我們只能盡量降低耦合度而無法在存在API調用關系的情況下消除耦合。為了提高依賴方(API調用者)的穩定性,我們應當努力使API穩定。
如何使API穩定?在設計API時應當站在API調用者而不是API提供者的角度,思考API的調用者需要什么,不關心什么,在這個原則上進行封裝/信息隱藏。
總結
- 模塊化的正交設計:高內聚、低耦合。
- 四個策略:前兩個策略解決如何劃分模塊的問題,后兩個策略解決模塊之間如何連接的問題。
總結
以上是生活随笔為你收集整理的Code Style Guide之正交设计浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ORACLE: LPAD 和 RPAD(
- 下一篇: winsmac最强滚动截屏工具