軟體設計Solid原則學習總結
阿新 • • 發佈:2019-02-08
軟體質量度量指標有正確性、可維護性、效率性等;其中正確性可以通過TDD來保證,可維護性可以通過規範程式碼、重構程式碼來提升,效率性需要平時或者後期對軟體的效能進行優化以達到所要的指標... 為了能讓專案組開發團隊都寫出CleanCode,需要在專案組制定相應的規範(包括命名規範、程式碼編寫規範、註釋規範、開發流程規範、文件規範),並持續應用宣貫。規範是指專案成員都需要遵循一定的規律和原則來開發軟體,使得專案成員之間能夠無障礙地閱讀、理解和處理物件。保證統一正確的風格,團隊成員可以更好的溝通交流。所以每一位開發成員在正式進行開發之前,都需閱讀和嚴格遵循相關規範。 保證Clean Code需要注意的事項很多,平時編碼注意程式碼中的壞味道,利用重構的思想來處理這些壞味道。比如使用抽取方法,抽取類,替換演算法,使用狀態和策略等設計模式替換一大堆的if語句等。在平時多多積累總結,才能寫出高質量的程式碼。 重構與設計模式有著密切的聯絡,而進行重構和設計模式的很多思想都是基於Solid原則的,所以理解Solid原則顯得尤為重要。 單一職責原則 Single Responsibility Principle SRP 對於一個類而言,引起他變化的原因應該只有一個,如果有多個,那麼應該把職責分離,讓一個類只做一件單一的事情,因為一個類做的事情越多,改動的概率越大;改動的概率越大,出錯的概率就越大。我覺得這也是最能體現高內聚低耦合思想的原則之一。 反例:該類有不屬於執行緒服務的QueryLog方法 public interface IThreadService{ public List<ThreadVO> QueryThread(String threadId); public boolean AddThread(ThreadVO thread) throws Exception; public List<LogVO> QueryLog(String objectId) throws Exception; } 正例:拆分成兩個類,降低介面間的耦合性 public interface IThreadService extends IBasicService<ThreadVO>{ public List<ThreadVO> QueryThread(String threadId); public boolean AddThread(ThreadVO thread) throws Exception; } public interface ILogService{ public List<LogVO> QueryLog(String objectId) throws Exception; } 開放封閉原則 Open-Close Principle OCP 開放封閉原則指對於擴充套件是開發的,對於修改的封閉的。在設計過程中,儘量保證我們的類或者模組不被修改的前提下可以進行擴充套件,通過新增類或模組的方式來新增功能。這是OOD的基石。 反例:對於修改siebel或smartsales的監控功能,都需要修改該方法 public class SystemMonitor{ public void Monitor(String systemName){ if(systemName.equalsIgnoreCase("siebel")){ ... } else if(systemName.equalsIgnoreCase("smartsales")){ ... } } } 正例:新增監控抽象類,如果需要實現監控功能就繼承該類,對於siebel和smartsales的監控功能都放在各自的類裡,如果需要修改只需要修改各自的類。 如果要新增MSM的監控,只需要增加一個MonitorMSM的類。這樣對於擴充套件就是開放的了。 public class SystemMonitor{ Monitor monitor; public SystemMonitor (Monitor monitor){ this.monitor = monitor; } public void Monitor(){ monitor.execute(); } } public abstract class Monitor { public abstract void execute(String url); } public class MonitorSmartSalesTomcat extends Monitor{ @Override public void execute(String url) { ... } } public class MonitorSiebelTomcat extends Monitor{ @Override public void execute(String url) { ... } } 里氏替換原則 Liskov Subtitution Principle LSP 對於能使用父類的地方,一定可以使用它的子類代替,替換後不能察覺出父類與子類的差別。對於正方形長方形、圓形橢圓形這樣的例子不滿足里氏替換原則。 里氏代換原則是實現開閉原則的重要方式之一,由於使用基類物件的地方都可以使用子類物件,因此在程式中儘量使用基類型別來對物件進行定義,而在執行時再確定其子類型別,用子類物件來替換父類物件。 反例:SystemMonitor 的MonitorSmartSalesTomcat和MonitorSiebelTomcat方法傳遞的引數都是子類,根據里氏替換原則,我們應該在定義時使用積累,在執行時在確定其子類型別。 public class SystemMonitor{ public void MonitorSmartSalesTomcat(MonitorSmartSalesTomcat system){ system.execute(); } public void MonitorSiebelTomcat(MonitorSiebelTomcat system){ system.execute(); } } public abstract class Monitor { public abstract void execute(String url); } public class MonitorSmartSalesTomcat{ @Override public void execute(String url) { ... } } public class MonitorSiebelTomcat extends{ @Override public void execute(String url) { ... } } 正例: public class SystemMonitor{ public void Monitor(Monitor system){ system.execute(); } } public abstract class Monitor { public abstract void execute(String url); } public class MonitorSmartSalesTomcat extends IMonitor{ @Override public void execute(String url) { ... } } public class MonitorSiebelTomcat extends IMonitor{ @Override public void execute(String url) { ... } } 介面隔離原則 Interface Segregation Principle ISP 使用多個專門的介面比使用一個總介面要好,應該根據客戶的需要提供不同的介面,不應該讓客戶依賴與他們不需要的方法。否則會產生不正常而且有害的耦合關係,如果一個客戶程式要求改動介面,會影響到其他的客戶程式。 反例:提供的執行緒介面有客戶不需要使用的QueryLog方法 public interface IThreadService{ public List<ThreadVO> QueryThread(String threadId); public boolean AddThread(ThreadVO thread) throws Exception; public List<LogVO> QueryLog(String objectId) throws Exception; } 正例:拆分成兩個介面,降低介面間的耦合性 public interface IThreadService extends IBasicService<ThreadVO>{ public List<ThreadVO> QueryThread(String threadId); public boolean AddThread(ThreadVO thread) throws Exception; } public interface ILogService{ public List<LogVO> QueryLog(String objectId) throws Exception; } 依賴倒轉原則 Dependence Inversion Principle DIP 依賴倒轉有以下幾點表述方式 1. 高層模組不應該依賴於低層模組。二者都應該依賴於抽象。 2. 抽象不應該依賴於細節。細節應該依賴抽象。 3. 要針對介面程式設計,而不是針對實現程式設計。 4. 傳遞引數,儘量引用層次高的類。 反例:SystemMonitor依賴於兩個具體的監控類 public class SystemMonitor{ public void execute(String systemName){ if(systemName.equalsIgnoreCase("siebel")){ MonitorSiebelTomcat monitor = new MonitorSiebelTomcat(); monitor.execute(); } else if(systemName.equalsIgnoreCase("smartsales")){ MonitorSmartSalesTomcat monitor = new MonitorSmartSalesTomcat(); monitor.execute(); } } } public class MonitorSmartSalesTomcat{ @Override public void execute(String url) { ... } } public class MonitorSiebelTomcat extends{ @Override public void execute(String url) { ... } } 正例:新增監控抽象類,SystemMonitor依賴於抽象,而不依賴於具體的實現 public class SystemMonitor{ IMonitor monitor; public SystemMonitor(IMonitor monitor){ this.monitor = monitor; } public void Monitor(){ monitor.execute(); } } public abstract class Monitor { public abstract void execute(String url); } public class MonitorSmartSalesTomcat extends IMonitor{ @Override public void execute(String url) { ... } } public class MonitorSiebelTomcat extends IMonitor{ @Override public void execute(String url) { ... } } 2016.07.21