摘要:軟件設(shè)計(jì)一直是開(kāi)發(fā)周期中最重要的階段,在設(shè)計(jì)彈性和靈活的體系結(jié)構(gòu)的花費(fèi)的時(shí)間越多,在將來(lái)出現(xiàn)變更時(shí)就越節(jié)省時(shí)間。在本文中,我們將討論有助于創(chuàng)建易于維護(hù)和可擴(kuò)展的軟件的關(guān)鍵設(shè)計(jì)原則。
翻譯: 瘋狂的技術(shù)宅
來(lái)源: Programmer Gate
原文標(biāo)題: Software design principles
英文原文: http://programmergate.com/sof...
說(shuō)明:本專欄文章首發(fā)于公眾號(hào):jingchengyideng 。
軟件設(shè)計(jì)一直是開(kāi)發(fā)周期中最重要的階段,在設(shè)計(jì)彈性和靈活的體系結(jié)構(gòu)的花費(fèi)的時(shí)間越多,在將來(lái)出現(xiàn)變更時(shí)就越節(jié)省時(shí)間。需求總是變化的,如果不定期添加或維護(hù)功能,軟件將出現(xiàn)為遺留問(wèn)題,并且變更成本是根據(jù)系統(tǒng)的結(jié)構(gòu)和體系結(jié)構(gòu)來(lái)確定的。在本文中,我們將討論有助于創(chuàng)建易于維護(hù)和可擴(kuò)展的軟件的關(guān)鍵設(shè)計(jì)原則。
1. 一個(gè)實(shí)際的場(chǎng)景假設(shè)老板要求你寫一個(gè)將word文檔轉(zhuǎn)換成PDF的程序。這個(gè)任務(wù)看起來(lái)很簡(jiǎn)單,只需找到一個(gè)可靠的庫(kù),它可以將word文檔轉(zhuǎn)換成PDF,并把它集成到你的程序中。在做了一些研究之后,你最終決定使用 Aspose.words 框架并創(chuàng)建了以下類:
代碼: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(); } }
生活很簡(jiǎn)單,一切都很順利!!
需求總是變化幾個(gè)月后,一些用戶要求支持也 excel 文檔,所以你又做了一些研究,決定使用ascell.cell 。然后你找到你原來(lái)的類,并添加了一個(gè)名為 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(); } } }
該代碼可以為新用戶正常正常,而且仍然可以按照預(yù)期的方式為現(xiàn)有的用戶工作,但是一些糟糕的設(shè)計(jì)氣味開(kāi)始出現(xiàn)在代碼中,這樣做是不完美的,當(dāng)再一個(gè)新的文檔類型時(shí),我們將無(wú)法輕松修改這個(gè)類。
代碼重復(fù):正如你所看到的,在if/else塊存在類似的代碼,如果有一天再添加不同的擴(kuò)展,那么將會(huì)出現(xiàn)大量的重復(fù)。如果我們決定返回一個(gè)文件而不是一個(gè) byte[] 那么就必須在所有的塊中做相同的修改。
剛性:所有的轉(zhuǎn)換算法都是在同一種方法中進(jìn)行耦合的,所以如果你改變了一些算法,其他的算法也會(huì)隨之受到影響。
固定:上面的方法直接依賴于documentType字段,假如一些用戶在調(diào)用convertToPDF()之前忘記了設(shè)置這個(gè)字段,那將得不到預(yù)期的結(jié)果,我們也不能在任何其他項(xiàng)目中重用該方法,因?yàn)樗蕾囉谧侄巍?/p>
高級(jí)模塊與框架之間的耦合:如果將來(lái)我們決定用更可靠的方式替換 Aspose 框架,那么最終修將會(huì)改整個(gè) PDFConverter 類,并且會(huì)有許多用戶受到影響。
正確的方式通常情況下,并不是所有的開(kāi)發(fā)人員都能夠預(yù)見(jiàn)未來(lái)的變化。因此,他們中的大多數(shù)人將會(huì)像我們第一次實(shí)現(xiàn)的那樣,完全實(shí)現(xiàn)程序,但是在第一次改變之后,情況就會(huì)變得很明顯,將來(lái)會(huì)發(fā)生類似的變化。所以,好的開(kāi)發(fā)人員將會(huì)為了盡可能減少將來(lái)變更的成本使用正確的方式,而不是用if / else塊實(shí)現(xiàn)。所以我們?cè)诒┞兜墓ぞ撸≒DFConverter)和低級(jí)轉(zhuǎn)換算法之間創(chuàng)建一個(gè)抽象層,并將每個(gè)算法移動(dòng)到一個(gè)多帶帶的類中,如下所示:
代碼: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); } }
當(dāng)調(diào)用convertToPDF()時(shí),我們強(qiáng)制用戶決定應(yīng)該使用哪種轉(zhuǎn)換算法。
2. 這樣做的好處是什么?!關(guān)注點(diǎn)分離(高內(nèi)聚/低耦合): 現(xiàn)在 PDFConverter 類對(duì)程序中使用的轉(zhuǎn)換算法一無(wú)所知,它主要關(guān)注的是為用戶提供各種轉(zhuǎn)換特性,而關(guān)心轉(zhuǎn)換是如何進(jìn)行的?,F(xiàn)在,我們可以隨時(shí)替換底層轉(zhuǎn)換框架,只要我們能夠返回預(yù)期的結(jié)果,就不會(huì)人會(huì)知道。
單一職責(zé): 創(chuàng)建抽象層并將每個(gè)動(dòng)態(tài)行為移到多帶帶的類之后,我們實(shí)際上刪除了 convertToPDF() 方法在以前初始設(shè)計(jì)中的的多重職責(zé),現(xiàn)在它只有一個(gè)職責(zé),就是將用戶的請(qǐng)求委托給抽象的轉(zhuǎn)換層。此外,轉(zhuǎn)換器接口的每個(gè)實(shí)現(xiàn)類現(xiàn)在都有一個(gè)單一的責(zé)任,即將某些文檔類型轉(zhuǎn)換為PDF。因此,每個(gè)組件都有一個(gè)被修改的理由,因此沒(méi)有回歸。
打開(kāi)/關(guān)閉程序: 我們的程序現(xiàn)在對(duì)擴(kuò)展開(kāi)放,并且對(duì)修改關(guān)閉,當(dāng)我們?cè)谖磥?lái)想要支持一些新的文檔類型時(shí),只需要從 Converter 接口創(chuàng)建一個(gè)新的實(shí)現(xiàn)類,并且不需要修改 PDFConverter 工具,因?yàn)楝F(xiàn)在我們的工具依賴于抽象。
3. 從這篇文章中學(xué)到的設(shè)計(jì)原則以下是構(gòu)建應(yīng)用程序架構(gòu)時(shí)要遵循的最佳設(shè)計(jì)實(shí)踐:
將程序劃分為幾個(gè)模塊,并在每個(gè)模塊的頂部添加一個(gè)抽象層。
有利于抽象實(shí)現(xiàn):一定要依賴抽象層,這將有利于程序?qū)?lái)的擴(kuò)展,抽象應(yīng)該應(yīng)用于程序的動(dòng)態(tài)部分(最有可能經(jīng)常改變的部分),不一定在所有的部分,因?yàn)樵谶^(guò)度使用的情況下是你的代碼變得非常復(fù)雜。
確定程序的不同方面,并將它們與保持不變的部分分開(kāi)。
不要重復(fù)自己:永遠(yuǎn)把重復(fù)的功能在一些工具類中,并使其通過(guò)整個(gè)程序訪問(wèn),這會(huì)使你的修改變得容易得多。
通過(guò)抽象層隱藏低級(jí)實(shí)現(xiàn):低級(jí)模塊有很高的可能性會(huì)定期更改,因此將其與高級(jí)模塊分開(kāi)。
每個(gè)類/方法/模塊應(yīng)該有一個(gè)理由去改變,所以為了減少回歸,總是給每一個(gè)類單一的責(zé)任。
關(guān)注點(diǎn)分離:每個(gè)模塊都知道其他模塊做什么,但是它自己不知道該怎么做。
作者簡(jiǎn)介:
HUSSEINTEREK: programmergate.com的創(chuàng)始人,對(duì)軟件工程和所有與java相關(guān)的東西都充滿激情。
歡迎掃描二維碼關(guān)注公眾號(hào),每天推送我翻譯的技術(shù)文章。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67515.html
摘要:開(kāi)閉原則軟件實(shí)體類,模塊,函數(shù)應(yīng)該是可以擴(kuò)展的,而不是修改。函數(shù)并不符合開(kāi)閉原則,因?yàn)橐坏┯行聞?dòng)物出現(xiàn),它需要修改代碼。 By Chidume Nnamdi | Oct 9, 2018 原文 面向?qū)ο蟮木幊填愋蜑檐浖_(kāi)發(fā)帶來(lái)了新的設(shè)計(jì)。 這使開(kāi)發(fā)人員能夠在一個(gè)類中組合具有相同目的/功能的數(shù)據(jù),來(lái)實(shí)現(xiàn)單獨(dú)的一個(gè)功能,不必關(guān)心整個(gè)應(yīng)用程序如何。 但是,這種面向?qū)ο蟮木幊踢€是會(huì)讓開(kāi)發(fā)者困惑或...
摘要:設(shè)計(jì)模式是軟件開(kāi)發(fā)人員在整個(gè)軟件開(kāi)發(fā)的過(guò)程中面臨普遍問(wèn)題的解決方案。這些作者被統(tǒng)稱為四人幫。根據(jù)這些作者的觀念,設(shè)計(jì)模式主要是基于一下幾種面向?qū)ο蟮脑O(shè)計(jì)原則。例如,單例模式表示使用單一對(duì)象。我們還將討論另外一個(gè)類別的設(shè)計(jì)模式。 原文鏈接譯者:smallclover個(gè)人翻譯,水平有限,如有錯(cuò)誤歡迎指出,謝謝! 設(shè)計(jì)模式-概述 設(shè)計(jì)模式體現(xiàn)了經(jīng)驗(yàn)豐富的面向?qū)ο筌浖_(kāi)發(fā)人員的最佳實(shí)踐。設(shè)計(jì)模...
摘要:想提升自己,還得多看書(shū)多看書(shū)多看書(shū)下面是我收集到的一些程序員應(yīng)該看得書(shū)單及在線教程,自己也沒(méi)有全部看完。共勉吧當(dāng)然,如果你有好的書(shū)想分享給大家的或者覺(jué)得書(shū)單不合理,可以去通過(guò)進(jìn)行提交。講師溫銘,軟件基金會(huì)主席,最佳實(shí)踐作者。 想提升自己,還得多看書(shū)!多看書(shū)!多看書(shū)!下面是我收集到的一些PHP程序員應(yīng)該看得書(shū)單及在線教程,自己也沒(méi)有全部看完。共勉吧!當(dāng)然,如果你有好的書(shū)想分享給大家的或者...
摘要:前端中的計(jì)算機(jī)領(lǐng)域的通常認(rèn)為起源于。并對(duì)其主要內(nèi)容作了自己的解讀。搬到另一個(gè)地區(qū)會(huì)導(dǎo)致名氣降低。年度報(bào)告,年最受歡迎的編程語(yǔ)言年上最流行的種編程語(yǔ)言及前十最火熱的項(xiàng)目排行榜,分別由及登頂。技術(shù)周刊由小組出品,匯聚一周好文章,周刊原文。 showImg(https://segmentfault.com/img/bVWHC4?w=1000&h=710); 本期推薦 反擊爬蟲(chóng),前端工程師的腦...
閱讀 3066·2023-04-25 18:54
閱讀 2591·2021-11-02 14:40
閱讀 3176·2021-09-23 11:58
閱讀 2424·2019-08-30 13:50
閱讀 1231·2019-08-29 12:46
閱讀 3117·2019-08-28 17:51
閱讀 679·2019-08-26 11:47
閱讀 897·2019-08-23 16:17