• 软件开发原则


    软件开发原则

    原则 介绍
    单一职责原则 一个类或模块应该只负责一项任务或功能
    开闭原则 软件实体(类、模块、函数等)应该对扩展开放,对修改关闭
    里氏替换原则 子类应该能够替换其父类并且不会破坏程序的正确性
    接口隔离原则 客户端不应该强制依赖它不需要的接口,即应该将接口拆分成更小的部分
    依赖倒置原则 高层模块不应该依赖于底层模块,它们都应该依赖于抽象接口
    迪米特法则 一个类应该对自己需要耦合或调用的类知道得最少(提供最简化调用接口)
    聚合复用原则 尽量使用对象组合,而不是继承来达到复用的目的

    以我个人的开源项目举例,来介绍几个基本软件开发原则的基本使用

    【SpringBoot集成OnlyOffice实现文档预览】

    单一职责原则

    模块的单一职责

    该开源项目可以作为一个jar引入,其承担的职责就是对onlyoffice集成,实现对office文件的预览和编辑。在领域驱动设计中,每个领域对象和聚合根通常应该遵循单一职责原则,确保它们只负责一个明确定义的领域职责。这有助于保持领域模型的清晰性,同时也符合单一职责原则的要求。

    类的单一职责

    我定义了如下几个接口类,其中每个类只负责了单一的职能

    存储服务接口

    copy
    package org.lboot.onlyoffice.loader; import org.lboot.onlyoffice.domain.Document; import java.io.InputStream; /** * @author kindear * office 文档存储服务 * 该服务与第三方或者本地文件系统集成 */ public interface OfficeStoreLoader { /** * 根据文件 key 获取文件信息 * @param fileKey * @return */ Document readFile(String fileKey); /** * 修改文件 * @param fileKey * @param stream * @return */ boolean writeFile(String fileKey, InputStream stream); }

    鉴权服务接口

    copy
    package org.lboot.onlyoffice.loader; /** * @author kindear * Office 鉴权信息加载 */ public interface OfficeAuthLoader { /** * 获取当前登录用户ID * @return */ default String getUserId(){ return "0"; } /** * 获取当前登录用户名称 * @return */ default String getUserName(){ return "guest"; } }

    配置接口

    copy
    package org.lboot.onlyoffice.loader; /** * @author kindear * OnlyOffice配置加载 */ public interface OfficeConfigLoader { /** * 获取客制化LOGO地址 * @return */ @Deprecated default String getCustomLogo(){ return ""; } /** * 获取默认语言 * 默认 zh-CN 中文 * @return */ default String getLang(){ return "zh-CN"; } /** * 获取回调地址 * @return */ default String getCallbackUrl(){ return ""; } }

    开闭原则

    对扩展开放,对修改关闭

    将我的项目作为依赖引入后,自然而然符合对修改关闭这个特点,

    集成的业务系统又可以基于上面所定义的接口,来拓展实现功能,满足对拓展开放

    具体可以查看【拓展】

    里氏替换原则

    子类可以扩展父类的功能,但不能改变父类原有的功能

    我在代码设计中加入了基于spring上下文的事件监听机制,该子类继承自父类ApplicationEvent,该实现没有改变父类可以被spring框架管理监听的特性,又拓展了新的字段属性,使得该子类可以在被spring管理监听的基础上,携带了更多参数。

    copy
    package org.lboot.onlyoffice.event; import lombok.Getter; import org.springframework.context.ApplicationEvent; import java.time.Clock; /** * @author kindear * office 文档编辑构建事件 传入文件ID 和 用户ID */ @Getter public class OfficeEditBuildEvent extends ApplicationEvent { String userId; String fileKey; public OfficeEditBuildEvent(Object source, String userId, String fileKey) { super(source); this.userId = userId; this.fileKey = fileKey; } public OfficeEditBuildEvent(Object source, Clock clock) { super(source, clock); } }

    接口依赖原则

    接口仅仅提供客户端需要的行为,即所需的方法,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口

    在完成配置项后,不需要用户关注底层的编辑回调,文件装载,文件信息获取如何实现,该依赖为用户提供了最简单的调用接口OfficeCtl,所有引入该依赖的,都只需要该类即可。

    copy
    package org.lboot.onlyoffice.service; import org.lboot.onlyoffice.domain.DocEditor; import org.lboot.onlyoffice.domain.Document; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletResponse; import java.util.Map; /** * @author kindear * onlyoffice 服务实现类 */ public interface OfficeCtl { /** * 根据文件后缀 获取office 中类型 * @param extName * @return 文件类型 */ String getDocumentType(String extName); /** * 构建远程文档访问 Document * @param remoteUrl * @return */ Document buildRemoteDocument(String remoteUrl); /** * 构建文档预览 DocEditor * @param document * @return */ DocEditor buildPreviewDocEditor(Document document); /** * 构建文档编辑 DocEditor * @param document * @return */ DocEditor buildEditDocEditor(Document document); /** * 预览远程文件 * @return file-temp */ @Deprecated ModelAndView previewRemoteFile(String remoteUrl, HttpServletResponse servletResponse); /** * 预览远程文件 * @param remoteUrl * @return */ ModelAndView previewRemoteFile(String remoteUrl); /** * 移动端预览远程文件 * @param remoteUrl * @return */ ModelAndView previewRemoteFileOnMobile(String remoteUrl); /** * 嵌入式预览远程文件 * @param remoteUrl * @return */ ModelAndView previewRemoteFileOnEmbedded(String remoteUrl); /** * 根据文件key 预览文件 * @param fileKey * @return 预览试图 */ ModelAndView previewFile(String fileKey); /** * 文件预览 * @param editor * @return */ ModelAndView previewFile(DocEditor editor); /** * 文件预览 制定预览标题 * @param editor * @param title * @return */ ModelAndView previewFile(DocEditor editor, String title); /** * 编辑远程文件 * @param remoteUrl * @return */ ModelAndView editRemoteFile(String remoteUrl); /** * 文件编辑 * @param fileKey * @return */ ModelAndView editFile(String fileKey); /** * 文件编辑 * @param document * @return */ ModelAndView editFile(Document document); /** * 文件编辑 * @param editor * @return */ ModelAndView editFile(DocEditor editor); /** * 编辑回调 * @param params * @return */ Object editCallback(Map params); /** * 将远程访问文件转化为 Pdf * @param remoteUrl * @return pdf 下载地址 */ String covertToPdf(String remoteUrl); /** * 将文件转化未 pdf * @param document * @return */ String covertToPdf(Document document); /** * 文件生成缩略图 * @param remoteUrl * @return */ String generateThumbnail(String remoteUrl); /** * 文件生成缩略图 * @param document * @return */ String generateThumbnail(Document document); }

    依赖倒置原则

    高层模块不应该依赖于底层模块,它们都应该依赖于抽象接口

    OfficeCtl接口的实现举例,注入的接口全都是抽象接口,无论是基于默认的服务实现还是拓展实现,都可以注入。

    copy
    @Slf4j @Service @AllArgsConstructor public class OfficeCtlImpl implements OfficeCtl { OnlyOfficeProperties officeProps; OfficeConfigLoader configLoader; OfficeAuthLoader authLoader; OfficeStoreLoader storeLoader; @Resource ApplicationContext context; //... }

    迪米特法则

    一个类应该对自己需要耦合或调用的类知道得最少(提供最简化调用接口)

    例如读取本地存储系统文件并预览的接口

    copy
    @SneakyThrows @Override public ModelAndView previewFile(String fileKey) { Document document = storeLoader.readFile(fileKey); DocEditor docEditor = buildPreviewDocEditor(document); return previewFile(docEditor); }

    我们只需要关注调用storeLoader.readFile(fileKey);可以获取对应的信息,对于该接口中如何获取文件并读取信息的实现不需要关注。

    合成复用原则

    OfficeCtl的实现类即是几种服务的合成复用的案例

  • 相关阅读:
    ROS1云课→30导航仿真演示
    基础—SQL—DQL(数据查询语言)分页查询
    解决javax.xml.parsers.DocumentBuilderFactory.setFeature(Ljava/lang/String;Z)V异常
    《敏捷无敌之DevOps时代》读后感
    apt和dpkg的源码下载链接
    Vue 访问外链失败问题
    费曼学习法(一)
    云原生的候选应用
    第二天:ALOAM前端讲解【第1部分】
    mysql 忘记 root 密码的解决办法(针对不同 mysql 版本)
  • 原文地址:https://www.cnblogs.com/masterchd/p/17678048.html