前言冗余代码向来是代码的一种坏味道,也是我们程序员要极力避免的 。今天我通过一个示例和大家分享下解决冗余代码的3个手段,看看哪个最好 。
问题描述为了描述这个问题,我将使用 FtpClient 作为示例 。要从 ftp 服务器获取一些文件,你需要先建立连接,下一步是登录,然后执行查看ftp文件列表、删除ftp文件,最后注销并断开连接,代码如下:
public class FtpProvider{private final FTPClient ftpClient;public FTPFile[] listDirectories(String parentDirectory) {try {ftpClient.connect("host", 22);ftpClient.login("username", "password");return ftpClient.listDirectories(parentDirectory);} catch (IOException ex) {log.error("Something went wrong", ex);throw new RuntimeException(ex);} finally {try {ftpClient.logout();ftpClient.disconnect();} catch (IOException ex) {log.error("Something went wrong while finally", ex);}}}public boolean deleteFile(String filePath) {try {ftpClient.connect("host", 22);ftpClient.login("username", "password");return ftpClient.deleteFile(filePath);} catch (IOException ex) {log.error("Something went wrong", ex);throw new RuntimeException(ex);} finally {try {ftpClient.logout();ftpClient.disconnect();} catch (IOException ex) {log.error("Something went wrong while finally", ex);}}}}正如上面代码所示,listDirectories和downloadFtpFile?中都包含了ftp连接、登录以及最后的注销操作,存在大量冗余的代码,那有什么更好的办法清理冗余代码呢?下面推荐3个做法,所有三个提出的解决方案都将实现以下 FtpProvider 接口,我将比较这些实现并选择更好的一个 。
public interface FtpProvider {FTPFile[] listDirectories(String directory) throws IOException;boolean deleteFile(String filePath) throws IOException;}1. 使用@Aspect 代理
- 首先创建一个注解, 用来注解需要代理的方法
@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface FtpOperation {}- 创建一个类实现 FtpProvider接口, 将注解添加到方法 listDirectories 和 deleteFile 中
@Slf4j@Serviceclass FtpProviderImpl implements FtpProvider {private final FTPClient ftpClient;@Overridepublic FTPFile[] listDirectories(String directory) throws IOException {return ftpClient.listDirectories(directory);}@Overridepublic boolean deleteFile(String filePath) throws IOException {return ftpClient.deleteFile(filePath);}}- 实现注解的代理切面逻辑
@Slf4j@Aspect@Component@RequiredArgsConstructorpublic class FtpOperationProxy {private final FTPClient ftpClient;@Around("@annotation(daniel.zielinski.redundancy.proxyaop.infrastructure.FtpOperation)")public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {try {ftpClient.connect("host", 22);ftpClient.login("username", "password");return joinPoint.proceed();} catch (IOException ex) {log.error("Something went wrong", ex);throw new RuntimeException(ex);} finally {try {ftpClient.logout();ftpClient.disconnect();} catch (IOException ex) {log.error("Something went wrong while finally", ex);}}}}所有用@FtpOperation? 注解的方法都会在这个地方执行joinPoint.proceed() 。2. 函数式接口- 创建一个函数式接口
@FunctionalInterfaceinterface FtpOperation<T, R> {R Apply(T t) throws IOException;}- 定义ftp执行模板
@RequiredArgsConstructor@Slf4j@Servicepublic class FtpOperationTemplate {private final FTPClient ftpClient;public <K> K execute(FtpOperation<FTPClient, K> ftpOperation) {try {ftpClient.connect("host", 22);ftpClient.login("username", "password");return ftpOperation.apply(ftpClient);} catch (IOException ex) {log.error("Something went wrong", ex);throw new RuntimeException(ex);} finally {try {ftpClient.logout();ftpClient.disconnect();} catch (IOException ex) {log.error("Something went wrong while finally", ex);}}}}- 定义实现类
@RequiredArgsConstructor@Slf4j@Serviceclass FtpProviderFunctionalInterfaceImpl implements FtpProvider {private final FtpOperationTemplate ftpOperationTemplate;public FTPFile[] listDirectories(String parentDirectory) {return ftpOperationTemplate.execute(ftpClient -> ftpClient.listDirectories(parentDirectory));}public boolean deleteFile(String filePath) {return ftpOperationTemplate.execute(ftpClient -> ftpClient.deleteFile(filePath));}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 如何编写高效的CSS代码?这五个技巧一定要知道!
- 云计算数据库的灾难恢复解决方案是如何演进的?
- Spring为什么使用三级缓存而不是两级解决循环依赖问题?
- ygomobile闪刀姬卡组导入 ygomobile卡组代码怎么用
- 数字视频压缩技术 视频压缩技术主要解决什么问题
- 笔记本黑屏后无法唤醒屏幕解决方法 电脑老是黑屏怎么处理
- 红星尔克股票代码?鸿星尔克有基金吗?
- 电脑自动重启频繁解决方法 win7电脑自动重启是什么原因
- 解决前列腺大问题 治疗前列腺炎肥大
- 硬盘无法格式化怎么办?电脑硬盘格式化不了的解决方法?
