翻译: 疯狂的技术宅 来源: Programmer Gate 原文标题: Software design principles 英文原文: http://programmergate.com/software-design-principles/
软件设计一直是开发周期中最重要的阶段,在设计弹性和灵活的体系结构的花费的时间越多,在将来出现变更时就越节省时间。需求总是变化的,如果不定期添加或维护功能,软件将出现为遗留问题,并且变更成本是根据系统的结构和体系结构来确定的。在本文中,我们将讨论有助于创建易于维护和可扩展的软件的关键设计原则。
假设老板要求你写一个将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块实现。所以我们在暴露的工具(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()时,我们强制用户决定应该使用哪种转换算法。
以下是构建应用程序架构时要遵循的最佳设计实践:
作者简介: HUSSEINTEREK: programmergate.com的创始人,对软件工程和所有与java相关的东西都充满激情。