编码艺术-代码架构的思考
一、前言
从入职到现在已有一年。想想现在与当初自己的期望虽有遗憾但也还是有所进步。我个人对自己的认知是敢于尝试与实践新的技术与新的理论,说大胆也不为过。因此工作中写的代码或多或少也被诟病、被批评、被质疑。但我觉得若人人都循规蹈矩、人人都不去尝试,那么谈何创新、谈何进步呢?终究是需要人去做那一颗划破静夜的流星。
二、背景
最近在对项目的SDK进行升级改造。考虑到要兼容之前用户的调用习惯,所以改造是需要很多讲究的,也引发了对代码架构的思考。在大多数时候我们在完成一个需求的时候,大部分人都是努力去完成它,即便给时间优化,我们往往也从代码规范、性能上进行优化,似乎没有人考虑可扩展性。当然这需要一定的前瞻性、也或许是因为我们缺乏对该功能的全局意识不知道该功能未来会发生如何变化。
三、案例阐述
- 1,业务A-组合服务间的协作。
在该业务场景下,多线程处理且需要多个服务组合使用,有些服务需要依托其他服务的处理信息。一般我们的处理的思路是根据其他服务的返回值进行判断再做处理。如果我们不做任何思考,就按照这个思路做下去,我觉得这样子,代码结构相对混乱,代码可扩展性也很差。比如我现在给这个业务新加了一个服务,其他服务都需依赖我得服务处理信息进行处理,这就要对代码结构进行调整了,代价高昂。示例伪代码如下:
public class Business{ private ServiceA serviceA; private ServiceB serviceB; public void invoke(){ if(serviceA.doSomething()){ serviceB.doSomething(); } } } interface class ServiceA{ boolean doSomething(); } interface class ServiceB{ boolean doSomething(); }
现在我们思考是否有其他成熟的框架解决过类型的业务?我们知道Servlet对于多线程对当前应用的感知是通过Context完成的。受此启发,这种涉及到多线程、多服务的组合调用我们可以给该业务场景绑定一个context,我们可以再任何服务通过获取context信息,以确定当前服务是否可继续执行。调整的代码结构:
public class Business{ private ServiceA serviceA; private ServiceB serviceB; private Context context; public void invoke(){ serviceA.doSomething(); if(context.hasSomeServiceError()){ // end return ; } } } interface class ServiceA{ void doSomething(); } interface class ServiceB{ void doSomething(); } class context{ /* 是否有其他服务执行失败 */ public boolean hasSomeServiceError(){} }
- 2,业务B-不同场景切换不同实现。
在该业务下,有多个场景,每个场景需要不同的逻辑。一般的思路是有多个场景,我们就定义多个实现,然后再一个服务方法中,通过不同的场景去选择不同的实现。用伪代码描述如下:
publis class Service{ public void invoke(type type){ switch(type){ // 场景为aType case aType: // 获取到aType的服务发起调用 getAtypeService().invoke(); break; } } }
但是这样带来的问题在于,你每次添加一个场景都需要去写一个获取该type对应服务的方法,并且到主方法里面去发起对该场景type的调用。这样子做是可以的,但是它增加了开发的复杂度。像这种频繁的场景切换对应不同的实现,我们想一想是否有遇到过类似的需求再其他地方有实现我们可借鉴呢?这个貌似我没有遇到过,但是我知道一个相似的理论:通道与管道。通道负责下达执行命令的指令,管道负责将命令送达到执行的地方。基于此我们可以将最外层的调用抽象层通道,里面不同的实现抽象为不同的管道。然后每个管道都有自己的标识,我们通过命令选择对应的管道去执行。优化后的代码结构:
public class ServiceChannel{ public void invoke(Type type){ // 发起调用 findPipeLine(type).invoke(); } private ServicePipeline findPipeLine(Type type){ // 找对应的管道,一般我们要求实现管道接口的类,都要注入到Spring上下文环境中 // 再这里我们可通过spring上下文获取到所有管道 } /** * 对于不同的场景我们只需要实现这个接口,注入到Spring上下文环境,无需其他任何操作,就可实现不同场景不同服务调用了 */ public static SerivcePipeline{ // 发起调用 void invoke(); // 管道类型 Tyep tyep(); } }
上面的实现主要将一些不必要的逻辑对用户进行屏蔽,以及解耦实现与调用的关联。
四、总结
归根结底,一份好的代码结构、必定是要考虑代码隔离、解耦等多方面的。对于这方面确实有待加强、后续看一下有关这方面的理论知识还是很有必要的
原文地址:https://www.cnblogs.com/enjoyall/p/11373762.html
- IT中的闰秒问题(r5笔记第85天)
- 浅谈exp/imp(下) (r5笔记第84天)
- 多线程编程学习五(线程池的创建)
- 再学习之Spring(面向切面编程).
- Hybris CronJob
- tomcat源码编译和环境搭建(r5笔记第83天)
- NumPy 将停止支持 Python 2,这里有一份给数据科学家的 Python 3 使用指导
- Apache solr(一).
- dataguard中MRP无法启动的问题分析和解决(r5笔记第82天)
- Apache solr(二).
- Git 使用技巧
- 4.训练模型之准备训练数据
- 关于dg broker的简单配置(r5笔记第99天)
- 三天速成 TensorFlow课件分享
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Oracle参数解析(OPEN_CURSORS)
- java_Collection、Map、泛型的使用
- java_线程、同步、线程池
- Oracle参数解析(nls_timestamp_format)
- Vue使用uuid-npm快速生成uuid,适用于多种场景
- WPF调用图片或资源(Uri)
- Hexo部署远程仓库(Conding、Gitee、Github)
- Linux下安装nginx
- CSS简笔画logo系列:纯CSS绘制“Adidas” Logo
- Electron + Vue跨平台桌面应用开发实战教程(一)
- java_抽象类、接口、多态的使用
- Electron + Vue跨平台桌面应用开发实战教程(二)
- Oracle参数解析(nls_length_semantics)
- 创建单页
- Electron + Vue跨平台桌面应用开发实战教程(三)