摘要:軟件設計一直是開發周期中最重要的階段,在設計彈性和靈活的體系結構的花費的時間越多,在將來出現變更時就越節省時間。在本文中,我們將討論有助于創建易于維護和可擴展的軟件的關鍵設計原則。
翻譯: 瘋狂的技術宅
來源: Programmer Gate
原文標題: Software design principles
英文原文: http://programmergate.com/sof...
說明:本專欄文章首發于公眾號:jingchengyideng 。
軟件設計一直是開發周期中最重要的階段,在設計彈性和靈活的體系結構的花費的時間越多,在將來出現變更時就越節省時間。需求總是變化的,如果不定期添加或維護功能,軟件將出現為遺留問題,并且變更成本是根據系統的結構和體系結構來確定的。在本文中,我們將討論有助于創建易于維護和可擴展的軟件的關鍵設計原則。
1. 一個實際的場景假設老板要求你寫一個將word文檔轉換成PDF的程序。這個任務看起來很簡單,只需找到一個可靠的庫,它可以將word文檔轉換成PDF,并把它集成到你的程序中。在做了一些研究之后,你最終決定使用 Aspose.words 框架并創建了以下類:
代碼:PDFConverter.java
/** * A utility class which converts a word document to PDF * @author Hussein * */ public class PDFConverter { /** * This method accepts as input the document to be converted and * returns the converted one. * @param fileBytes * @throws Exception */ public byte[] convertToPDF(byte[] fileBytes) throws Exception { // We"re sure that the input is always a WORD. So we just use //aspose.words framework and do the conversion. InputStream input = new ByteArrayInputStream(fileBytes); com.aspose.words.Document wordDocument = new com.aspose.words.Document(input); ByteArrayOutputStream pdfDocument = new ByteArrayOutputStream(); wordDocument.save(pdfDocument, SaveFormat.PDF); return pdfDocument.toByteArray(); } }
生活很簡單,一切都很順利!!
需求總是變化幾個月后,一些用戶要求支持也 excel 文檔,所以你又做了一些研究,決定使用ascell.cell 。然后你找到你原來的類,并添加了一個名為 documentType 的新字段,并修改了你的方法,代碼如下:
代碼:PDFConverter.java
public class PDFConverter { // we didn"t mess with the existing functionality, by default // the class will still convert WORD to PDF, unless the client sets // this field to EXCEL. public String documentType = "WORD"; /** * This method accepts as input the document to be converted and * returns the converted one. * @param fileBytes * @throws Exception */ public byte[] convertToPDF(byte[] fileBytes) throws Exception { if(documentType.equalsIgnoreCase("WORD")) { InputStream input = new ByteArrayInputStream(fileBytes); com.aspose.words.Document wordDocument = new com.aspose.words.Document(input); ByteArrayOutputStream pdfDocument = new ByteArrayOutputStream(); wordDocument.save(pdfDocument, SaveFormat.PDF); return pdfDocument.toByteArray(); } else { InputStream input = new ByteArrayInputStream(fileBytes); Workbook workbook = new Workbook(input); PdfSaveOptions saveOptions = new PdfSaveOptions(); saveOptions.setCompliance(PdfCompliance.PDF_A_1_B); ByteArrayOutputStream pdfDocument = new ByteArrayOutputStream(); workbook.save(pdfDocument, saveOptions); return pdfDocument.toByteArray(); } } }
該代碼可以為新用戶正常正常,而且仍然可以按照預期的方式為現有的用戶工作,但是一些糟糕的設計氣味開始出現在代碼中,這樣做是不完美的,當再一個新的文檔類型時,我們將無法輕松修改這個類。
代碼重復:正如你所看到的,在if/else塊存在類似的代碼,如果有一天再添加不同的擴展,那么將會出現大量的重復。如果我們決定返回一個文件而不是一個 byte[] 那么就必須在所有的塊中做相同的修改。
剛性:所有的轉換算法都是在同一種方法中進行耦合的,所以如果你改變了一些算法,其他的算法也會隨之受到影響。
固定:上面的方法直接依賴于documentType字段,假如一些用戶在調用convertToPDF()之前忘記了設置這個字段,那將得不到預期的結果,我們也不能在任何其他項目中重用該方法,因為它依賴于字段。
高級模塊與框架之間的耦合:如果將來我們決定用更可靠的方式替換 Aspose 框架,那么最終修將會改整個 PDFConverter 類,并且會有許多用戶受到影響。
正確的方式通常情況下,并不是所有的開發人員都能夠預見未來的變化。因此,他們中的大多數人將會像我們第一次實現的那樣,完全實現程序,但是在第一次改變之后,情況就會變得很明顯,將來會發生類似的變化。所以,好的開發人員將會為了盡可能減少將來變更的成本使用正確的方式,而不是用if / else塊實現。所以我們在暴露的工具(PDFConverter)和低級轉換算法之間創建一個抽象層,并將每個算法移動到一個多帶帶的類中,如下所示:
代碼:Converter.java
/** * This interface represents an abstract algorithm for converting * any type of document to PDF. * @author Hussein * */ public interface Converter { public byte[] convertToPDF(byte[] fileBytes) throws Exception; }
代碼:ExcelPDFConverter.java
/** * This class holds the algorithm for converting EXCEL * documents to PDF. * @author Hussein * */ public class ExcelPDFConverter implements Converter{ public byte[] convertToPDF(byte[] fileBytes) throws Exception { InputStream input = new ByteArrayInputStream(fileBytes); Workbook workbook = new Workbook(input); PdfSaveOptions saveOptions = new PdfSaveOptions(); saveOptions.setCompliance(PdfCompliance.PDF_A_1_B); ByteArrayOutputStream pdfDocument = new ByteArrayOutputStream(); workbook.save(pdfDocument, saveOptions); return pdfDocument.toByteArray(); }; }
代碼:WordPDFConverter.java
/** * This class holds the algorithm for converting WORD * documents to PDF. * @author Hussein * */ public class WordPDFConverter implements Converter { @Override public byte[] convertToPDF(byte[] fileBytes) throws Exception { InputStream input = new ByteArrayInputStream(fileBytes); com.aspose.words.Document wordDocument = new com.aspose.words.Document(input); ByteArrayOutputStream pdfDocument = new ByteArrayOutputStream(); wordDocument.save(pdfDocument, SaveFormat.PDF); return pdfDocument.toByteArray(); } }
代碼:PDFConverter.java
public class PDFConverter { /** * This method accepts as input the document to be converted and * returns the converted one. * @param fileBytes * @throws Exception */ public byte[] convertToPDF(Converter converter, byte[] fileBytes) throws Exception { return converter.convertToPDF(fileBytes); } }
當調用convertToPDF()時,我們強制用戶決定應該使用哪種轉換算法。
2. 這樣做的好處是什么?!關注點分離(高內聚/低耦合): 現在 PDFConverter 類對程序中使用的轉換算法一無所知,它主要關注的是為用戶提供各種轉換特性,而關心轉換是如何進行的。現在,我們可以隨時替換底層轉換框架,只要我們能夠返回預期的結果,就不會人會知道。
單一職責: 創建抽象層并將每個動態行為移到多帶帶的類之后,我們實際上刪除了 convertToPDF() 方法在以前初始設計中的的多重職責,現在它只有一個職責,就是將用戶的請求委托給抽象的轉換層。此外,轉換器接口的每個實現類現在都有一個單一的責任,即將某些文檔類型轉換為PDF。因此,每個組件都有一個被修改的理由,因此沒有回歸。
打開/關閉程序: 我們的程序現在對擴展開放,并且對修改關閉,當我們在未來想要支持一些新的文檔類型時,只需要從 Converter 接口創建一個新的實現類,并且不需要修改 PDFConverter 工具,因為現在我們的工具依賴于抽象。
3. 從這篇文章中學到的設計原則以下是構建應用程序架構時要遵循的最佳設計實踐:
將程序劃分為幾個模塊,并在每個模塊的頂部添加一個抽象層。
有利于抽象實現:一定要依賴抽象層,這將有利于程序將來的擴展,抽象應該應用于程序的動態部分(最有可能經常改變的部分),不一定在所有的部分,因為在過度使用的情況下是你的代碼變得非常復雜。
確定程序的不同方面,并將它們與保持不變的部分分開。
不要重復自己:永遠把重復的功能在一些工具類中,并使其通過整個程序訪問,這會使你的修改變得容易得多。
通過抽象層隱藏低級實現:低級模塊有很高的可能性會定期更改,因此將其與高級模塊分開。
每個類/方法/模塊應該有一個理由去改變,所以為了減少回歸,總是給每一個類單一的責任。
關注點分離:每個模塊都知道其他模塊做什么,但是它自己不知道該怎么做。
作者簡介:
HUSSEINTEREK: programmergate.com的創始人,對軟件工程和所有與java相關的東西都充滿激情。
歡迎掃描二維碼關注公眾號,每天推送我翻譯的技術文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/67515.html
摘要:開閉原則軟件實體類,模塊,函數應該是可以擴展的,而不是修改。函數并不符合開閉原則,因為一旦有新動物出現,它需要修改代碼。 By Chidume Nnamdi | Oct 9, 2018 原文 面向對象的編程類型為軟件開發帶來了新的設計。 這使開發人員能夠在一個類中組合具有相同目的/功能的數據,來實現單獨的一個功能,不必關心整個應用程序如何。 但是,這種面向對象的編程還是會讓開發者困惑或...
摘要:設計模式是軟件開發人員在整個軟件開發的過程中面臨普遍問題的解決方案。這些作者被統稱為四人幫。根據這些作者的觀念,設計模式主要是基于一下幾種面向對象的設計原則。例如,單例模式表示使用單一對象。我們還將討論另外一個類別的設計模式。 原文鏈接譯者:smallclover個人翻譯,水平有限,如有錯誤歡迎指出,謝謝! 設計模式-概述 設計模式體現了經驗豐富的面向對象軟件開發人員的最佳實踐。設計模...
摘要:前端中的計算機領域的通常認為起源于。并對其主要內容作了自己的解讀。搬到另一個地區會導致名氣降低。年度報告,年最受歡迎的編程語言年上最流行的種編程語言及前十最火熱的項目排行榜,分別由及登頂。技術周刊由小組出品,匯聚一周好文章,周刊原文。 showImg(https://segmentfault.com/img/bVWHC4?w=1000&h=710); 本期推薦 反擊爬蟲,前端工程師的腦...
閱讀 3082·2023-04-25 18:54
閱讀 2599·2021-11-02 14:40
閱讀 3200·2021-09-23 11:58
閱讀 2439·2019-08-30 13:50
閱讀 1245·2019-08-29 12:46
閱讀 3131·2019-08-28 17:51
閱讀 689·2019-08-26 11:47
閱讀 909·2019-08-23 16:17