成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

解決冗余代碼的三種方法,讓你的代碼更上一層樓

開發 前端
向 FtpProvider? 接口添加一個新方法,需要我們僅在一個地方進行更改。我們可以輕松地將我們的 FtpProvider? 注入到其他服務中。此解決方案的強項可能是 @FtpOperation? 注釋,它可以在 FtpProvider 上下文實現之外使用,但是將 Ftp 操作的邏輯劃分到單獨的類中并不是一個好方法。

?前言

冗余代碼向來是代碼的一種壞味道,也是我們程序員要極力避免的。今天我通過一個示例和大家分享下解決冗余代碼的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
@Service
class FtpProviderImpl implements FtpProvider {

private final FTPClient ftpClient;

@Override
public FTPFile[] listDirectories(String directory) throws IOException {
return ftpClient.listDirectories(directory);
}

@Override
public boolean deleteFile(String filePath) throws IOException {
return ftpClient.deleteFile(filePath);
}
}
  • 實現注解的代理切面邏輯
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public 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. 函數式接口

  • 創建一個函數式接口
@FunctionalInterface
interface FtpOperation<T, R> {

R apply(T t) throws IOException;
}
  • 定義ftp執行模板
@RequiredArgsConstructor
@Slf4j
@Service
public 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
@Service
class 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));
}
}

我們正在 FtpOperationTemplate? 上執行方法 execute? 并且我們正在傳遞 lambda? 表達式。我們將放入 lambda? 中的所有邏輯都將代替 ftpOperation.apply(ftpClient) 函數執行。

3. 模板方法

  • 創建一個抽象的模板類
@RequiredArgsConstructor
@Slf4j
@Service
abstract class FtpOperationTemplate<T, K> {

protected abstract K command(FTPClient ftpClient, T input) throws IOException;

public K execute(FTPClient ftpClient, T input) {
try {
ftpClient.connect("host", 22);
ftpClient.login("username", "password");
return command(ftpClient, input);
} 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);
}
}
}

}
  • 列出ftp目錄listDirectories方法的實現
@Slf4j
@Service
class FtpOperationListDirectories extends FtpOperationTemplate<String, FTPFile[]> {

@Override
protected FTPFile[] command(FTPClient ftpClient, String input) throws IOException {
return ftpClient.listDirectories(input);
}
}
  • 刪除文件deleteFile方法的實現
@Slf4j
@Service
class FtpOperationDeleteFile extends FtpOperationTemplate<String, Boolean> {

@Override
protected Boolean command(FTPClient ftpClient, String input) throws IOException {
return ftpClient.deleteFile(input);
}
}
  • 實現FtpProvider接口
@RequiredArgsConstructor
@Slf4j
@Service
public class FtpProviderTemplateImpl implements FtpProvider {

private final FtpOperationTemplate<String, FTPFile[]> ftpOperationListDirectories;
private final FtpOperationTemplate<String, Boolean> ftpOperationDeleteFile;
private final FTPClient ftpClient;

public FTPFile[] listDirectories(String parentDirectory) {
return ftpOperationListDirectories.execute(ftpClient, parentDirectory);
}

public boolean deleteFile(String filePath) {
return ftpOperationDeleteFile.execute(ftpClient, filePath);
}
}

我們正在 FtpOperationTemplate? 上執行方法 execute? 并在那里傳遞我們的參數。因此執行方法的邏輯對于 FtpOperationTemplate 的每個實現都是不同的。

總結

我們現在來比較下上面種方式:

  • @Aspect切面方式實現

向 FtpProvider? 接口添加一個新方法,需要我們僅在一個地方進行更改。我們可以輕松地將我們的 FtpProvider? 注入到其他服務中。此解決方案的強項可能是 @FtpOperation? 注釋,它可以在 FtpProvider 上下文實現之外使用,但是將 Ftp 操作的邏輯劃分到單獨的類中并不是一個好方法。

  • 函數式接口實現

向接口 FtpProvider? 添加一個新方法,需要我們僅在一個地方進行更改。我們可以輕松地將我們的 FtpProvider 注入到其他服務中。我們將ftp操作的邏輯封裝在一個類中。相對于上面的方式,我們也沒有用到AOP的庫,所以我個人還是比較推薦的。

  • 模板方法實現

向接口 FtpProvider? 添加一個新方法,需要我們在兩個地方進行更改。我們需要添加一個新的類,會導致類爆炸,另外,我們還需要將實現注入到 FtpProvider。

如果是你,你會選擇哪種方式呢?還是有更好的方法?

責任編輯:武曉燕 來源: JAVA旭陽
相關推薦

2021-03-25 15:07:50

編程技術工具

2014-08-18 14:54:54

Git

2017-07-27 08:38:51

JavaLinux

2011-03-31 09:51:45

Windows XP

2012-05-28 14:18:33

Web

2023-09-24 23:07:24

流量抑制風暴控制

2011-03-31 09:57:54

Windows XP

2023-04-26 13:55:00

Python開發技能

2021-01-21 11:24:16

智能安全首席信息安全官CISO

2023-12-19 18:08:47

MySQL方法優化查詢

2019-08-26 14:53:32

數據中心運維管理宕機

2019-08-26 10:10:57

數據中心運維宕機

2015-03-30 09:48:33

程序員更上一層樓

2023-11-01 13:34:37

Python

2009-10-23 14:46:43

2017-07-31 17:54:04

IT技術周刊

2024-06-20 13:22:13

C++11C++模板

2023-07-04 08:33:46

Python對象編程

2013-06-06 06:52:28

Ubuntu 13.0

2023-07-21 08:01:13

CSSInherit?
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级一级毛片免费看 | 欧美日高清视频 | 成人免费视频网站在线看 | 亚洲日本成人 | 国产精品久久久久久婷婷天堂 | 婷婷久 | 在线免费观看黄网 | 久久久91精品国产一区二区三区 | 大学生a级毛片免费视频 | 91精品国产综合久久久久久 | 久久久成人网 | 午夜电影网站 | 欧美国产日韩成人 | 日韩一区二区在线播放 | 小早川怜子xxxxaⅴ在线 | 国产91丝袜 | 国产精品99久久久久久久vr | 精品欧美一区二区三区久久久小说 | 亚洲免费一区二区 | xxxxx免费视频 | 亚洲毛片网站 | 亚洲一区 中文字幕 | 欧美黑人体内she精在线观看 | 自拍视频国产 | 国产一区二区三区 | 国产一区二区三区在线 | 我爱操| 精品在线观看一区 | 中日韩欧美一级片 | 日本福利一区 | 国产精品99久久久久久宅男 | 久久网一区二区 | 日韩精品一区二区三区在线观看 | 亚洲三区视频 | 国产一区不卡 | 97国产精品| 国产一区欧美一区 | 午夜精品一区二区三区免费视频 | 日韩一区二区在线视频 | 久久久久无码国产精品一区 | 久久久男人的天堂 |