当前位置: 首页 > news >正文

建立自我/推广优化工具

建立自我,推广优化工具,互联网如何做旅游网站,照片图片制作接 设计之附件上传与下载 1. 前言 距离上一篇已经四个月了,该组件也在公司内部广泛使用。正所谓“唯一的不变就是变化本身”,随着应用范围的增大,意料之外的需求也就随之产生了。比如最近碰到的一个。感觉最终的解决方案比较有代表性&#x…

接 设计之附件上传与下载

1. 前言

距离上一篇已经四个月了,该组件也在公司内部广泛使用。正所谓“唯一的不变就是变化本身”,随着应用范围的增大,意料之外的需求也就随之产生了。比如最近碰到的一个。感觉最终的解决方案比较有代表性,所以在这里表述下,希望对他人能有所帮助。再次声明本人对设计的理解完全是靠自己一点点悟出来的,所以有什么纰漏在所难免,还望不吝赐教。

需求是这样的,在最初的设计中,我们在进行配置文件设计时,上传和下载的地址被设置为只允许设置为一个。但最近这个需求就是需要颠覆这个要求。详细的业务场景就不说了,主要的需求就是允许设置多个地址,然后在下载时,从前往后遍历,直到找到为止。

2. 思考

经过近一个小时的冷静和调整,在脑海里转了无数次之后,终于大概地将应对本次需求的方案敲定。考虑大概如下:
1. 首先这段逻辑肯定不能写死在主体逻辑里面。
2. 个人也不希望增加一个额外的配置项,才迭代到第二个版本就需要作出这样的抉择,显得框架的适应性太差了。
3. 本次的需求其实是非常具体的,我们应该站在一个更高的层面上看待这个问题。也就是说我们要设计出一个通用的场景,本次需求只是该通用场景下的特殊情形。

3. 解决方案

3.1 契约

基于上面的思路,于是有了如下的接口定义

/*** 抉择者* @author LQ**/
public interface KanqBasePathDeterminer {/*** @param currentOperater 当前进行附件操作的操作实例* @param invocation 直接来自Mybatis, 封装了本次进行附件操作的方法的相关信息* @return 最终挑选出的根路径*/String determine(AffixOperater currentOperater,Invocation invocation);
}

回顾整个需求,我们:
1. 最终所关心的是满足要求的BasePath,
2. 而引起变化的则是在一堆外部的变化因素影响。
3. 因此我们最终敲定了以上的接口。

顺势就有了如下三个实现类:

3.2 KanqBasePathDeterminerSingle实现类

等同于需求升级前的版本。直接从配置文件中读取相应的值作为BasePath。

/*** <p>配置文件中只有一个显式的基路径 : &lt;setting name="affixBasePath" value="E:/tmp/logs/" /&gt;* <p>此时直接从配置文件中读取即可* @author LQ**/
class KanqBasePathDeterminerSingle implements  KanqBasePathDeterminer, IConfigAware{private ConfigFile config;@Overridepublic String determine(AffixOperater currentOperater, Invocation invocation) {return config.getAffixBasePath();}@Overridepublic void setConfig(ConfigFile config) {this.config = config;       }
}

3.3 KanqBasePathDeterminerSimpleMulti实现类

该实现类就是满足当前需求的版本。

相关配置文件

<settings><setting name="affixPathType" value="file" /><!-- 多个路径之间使用 ; 进行分割。 --><setting name="affixBasePath" value="E:/tmp/;E:/;D:/" />
</settings>

具体实现类

/*** <p>配置文件中有 ; 分割的多个基路径 : &lt;setting name="affixBasePath" value="E:/tmp/logs/;E:/;D:/" /&gt;* @author LQ**/
class KanqBasePathDeterminerSimpleMulti implements  KanqBasePathDeterminer, IConfigAware{private ConfigFile config;@Overridepublic String determine(AffixOperater currentOperater, Invocation invocation) {final Method method = invocation.getMethod();final String methodName = method.getName();final String affixBasePath = config.getAffixBasePath();final String[] splitArr = affixBasePath.split(";");     // 上传操作, 取第一个路径// FIXME 这里依赖于方法名, 这样并不好....if (methodName.contains("upload")) {            return splitArr[0];}final String relativePath = (String)invocation.getArgs()[0];for (final String basePath : splitArr) {if (currentOperater.isExist(FilenameUtil.concat(basePath, relativePath))) {return basePath;}}return null;}@Overridepublic void setConfig(ConfigFile config) {this.config = config;       }
}

3.4 KanqBasePathDeterminerCustom实现类

完全自定义逻辑。由用户通过实现KanqBasePathDeterminer接口来完成完全自主的自定义逻辑。

/*** <p>配置文件中有 . 分割的完整类名 : &lt;setting name="affixBasePath" value="com.xx.yy.zzDeterminer" /&gt;* <p> 完全由用户自定义* @author LQ**/
class KanqBasePathDeterminerCustom implements  KanqBasePathDeterminer, IConfigAware{private ConfigFile config;@Overridepublic String determine(AffixOperater currentOperater, Invocation invocation) {final String affixBasePath = config.getAffixBasePath();// 实例化用户的自定义类final KanqBasePathDeterminer customDeterminer = ClassUtil.<KanqBasePathDeterminer>newInstance(affixBasePath);       return config.config(customDeterminer).determine(currentOperater,invocation);       }@Overridepublic void setConfig(ConfigFile config) {this.config = config;       }
}

3.5 KanqBasePathDeterminerFactory

我们最终使用工厂模式隐藏构建细节。对外只暴露最开始定义的接口,将实现的细节隐藏起来,这也是为什么会将三个实现类的访问修饰符设置为package的原因。

/*** 工厂模式* @author LQ**/
public class KanqBasePathDeterminerFactory {public static KanqBasePathDeterminer match(final ConfigFile config){final String affixBasePath = config.getAffixBasePath();// 如果 affixBasePath有以下表现 ,我们可能就需要在运行时才决定真正上传/下载的基本路径  //    1. 以 ; 分割, 则猜测为 多路径抉择,               -- 此时我们会将其规约为下面这种情况//    2. 以 . 分割, 则猜测有自定义的实现规则来进行路径抉择 -- 此时为自定义类实现       if (affixBasePath.contains(";")) {return new KanqBasePathDeterminerSimpleMulti();}else if(affixBasePath.contains(".") && ClassUtil.isPresent(affixBasePath, null)){return new KanqBasePathDeterminerCustom();}else{return new KanqBasePathDeterminerSingle();}}
}

2.6 并入主体逻辑

AffixOperaterManager中,在将主体逻辑分发给各个附件操作实例前,挑选出满足本次附件操作要求的BasePath。

这里就只出下载相关的实现逻辑,上传的思路是一样的。

@Override
public KanqResource download(String path) {// 必须在这里先处理一次, 再传递给下面的方法;path = preDealPath(path);final String finalPath = determineFinalFullath(path, "download", new Object[] { path });return affixOperaterAdapter.doDwonload(finalPath);
}/*** 预处理* @param path* @return*/
private String preDealPath(String path) {while (path.startsWith("/") || path.startsWith("\\")) {path = path.substring(1);}return path;
}private final String determineFinalFullath(String path, final String methodName, Object[] args) {       final String basePath = determineKanqBasePath(methodName, args);final String finalPath = FilenameUtil.concat(basePath, path);return finalPath;
}private String determineKanqBasePath(final String methodName, Object[] args) {KanqBasePathDeterminer determiner = KanqBasePathDeterminerFactory.match(configFile);determiner = configFile.config(determiner);Class<?>[] parameterTypes = new Class<?>[args.length];for (int i = 0; i < args.length; i++) {Object arg = args[i];parameterTypes[i] = arg.getClass();}final Method method = ReflectUtil.getMethod(this.getClass(), methodName, parameterTypes);       Invocation invocation = new Invocation(this, method, args);return determiner.determine(affixOperaterAdapter, invocation);
}

3. 回顾

刚刚接到这个需求时,内心还是有点小激动的,毕竟检验之前的设计的机会终于来了,一个好的构架的最基本也是最重要的要素之一就是能从容面对需求的变更,少量的改动就能在确保现有功能完整的前提下适应新需求的增加和改变

在真正开始之后突然觉得好陌生,最开始还以为是好几个月没碰了,代码有些生疏的缘故。细细回想之下,发现是因为过去两周都在编写其他框架的说明文档和给同事的培训文档,以及一些公司马上要使用到的新的框架和组件的了解。已经快一个月没有进行架构和设计的思考总结了。现世报也太快了吧。

  1. 设计之附件上传与下载
http://www.lbrq.cn/news/1044253.html

相关文章:

  • 官网建站模板库/石家庄seo结算
  • 建站论坛/广告营销平台
  • 开发商城网站开发/seo网络优化专员
  • 新建网站如何推广/如何优化seo
  • 网站做seo推广方案/网站代发外链
  • 建设机械网站热线电话/无货源电商怎么做
  • 在哪了做网站/博客seo优化技术
  • 优秀茶叶网站设计/网站设计公司哪家专业
  • 无锡游戏网站建设公司/人员优化方案
  • 做设计私活的网站/市场营销主要学什么
  • 备案网站名称更改/seo一个月赚多少钱
  • 建设金融网站/全国疫情最新消息今天新增
  • c语言开发网站后端/世界杯排名
  • 凡科建网站怎么做阴影立体/可以免费打开网站的软件
  • 网站建设方案及报价单/qq群引流推广平台
  • wordpress分页太丑/厦门seo哪家强
  • 长沙网站排名技术/长春seo优化
  • 做网站用哪个eclipse/百度广告电话号码是多少
  • 南昌优易科 网站建设/山东疫情最新消息
  • 地推网/莱芜seo
  • 杭州论坛网/二十条优化措施全文
  • 各类专业网站建设/最近的电脑培训学校
  • 珠海网站建设有限公司/网站设计报价方案
  • 美国淘宝代购网站建设/郑州厉害的seo顾问公司
  • 网站建设 源代码归属/搜索优化的培训免费咨询
  • 房产证/网站seo排名培训
  • 广东同江医院网站建设/2023免费推广入口
  • 网站源码下载了属于侵权吗/百度推广登陆入口
  • 腾讯网站站内面包屑导航/厦门网站推广优化哪家好
  • wordpress 动态网站/自己怎么做引流推广
  • redis(2)-java客户端使用(IDEA基于springboot)
  • MyBatis进阶:动态SQL、多表查询、分页查询
  • BroadcastChannel:轻松实现前端跨页面通信
  • pytorch+tensorboard+可视化CNN
  • Kotlin反射详解
  • 非常简单!从零学习如何免费制作一个lofi视频