gpt4 book ai didi

java - 如何在我的 HttpClient 执行程序中遵循单一职责原则?

转载 作者:IT老高 更新时间:2023-10-28 13:55:28 24 4
gpt4 key购买 nike

我正在使用 RestTemplate作为我的 HttpClient 执行 URL,服务器将返回一个 json 字符串作为响应。客户将通过传递 DataKey 对象来调用此库,其中包含 userId

  • 使用给定的 userId,我将找出可以访问哪些机器来获取数据,然后将这些机器存储在 LinkedList 中,以便我可以按顺序执行。
  • 之后我会检查第一个主机名是否在阻止列表中。如果它不在阻止列表中,那么我将使用列表中的第一个主机名创建一个 URL 并执行它,如果响应成功则返回响应。但是假设第一个主机名在阻止列表中,那么我会尝试获取列表中的第二个主机名并制作 url 并执行它,所以基本上,首先找到不在列表中的主机名在创建 URL 之前阻止列表
  • 现在,假设我们选择了不在阻止列表中的第一个主机名并执行了 URL,但不知何故服务器已关闭或没有响应,那么我将执行列表中的第二个主机名并继续执行此操作,直到您获得成功响应。 但请确保它们不在阻止列表中,因此我们需要遵循上述要点。
  • 如果所有服务器都关闭或在阻止列表中,那么我可以简单地记录并返回服务不可用的错误。

下面是我的 DataClient 类,客户将调用它,他们会将 DataKey 对象传递给 getData 方法。

public class DataClient implements Client {

private RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
private ExecutorService service = Executors.newFixedThreadPool(15);

public Future<DataResponse> getData(DataKey key) {
DataExecutorTask task = new DataExecutorTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);

return future;
}
}

下面是我的 DataExecutorTask 类:

public class DataExecutorTask implements Callable<DataResponse> {

private DataKey key;
private RestTemplate restTemplate;

public DataExecutorTask(DataKey key, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.key = key;
}

@Override
public DataResponse call() {
DataResponse dataResponse = null;
ResponseEntity<String> response = null;

MappingsHolder mappings = ShardMappings.getMappings(key.getTypeOfFlow());

// given a userId, find all the hostnames
// it can also have four hostname or one hostname or six hostname as well in the list
List<String> hostnames = mappings.getListOfHostnames(key.getUserId());

for (String hostname : hostnames) {
// If host name is null or host name is in local block list, skip sending request to this host
if (ClientUtils.isEmpty(hostname) || ShardMappings.isBlockHost(hostname)) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.exchange(url, HttpMethod.GET, key.getEntity(), String.class);

if (response.getStatusCode() == HttpStatus.NO_CONTENT) {
dataResponse = new DataResponse(response.getBody(), DataErrorEnum.NO_CONTENT,
DataStatusEnum.SUCCESS);
} else {
dataResponse = new DataResponse(response.getBody(), DataErrorEnum.OK,
DataStatusEnum.SUCCESS);
}

break;
// below codes are duplicated looks like
} catch (HttpClientErrorException ex) {
HttpStatusCodeException httpException = (HttpStatusCodeException) ex;
DataErrorEnum error = DataErrorEnum.getErrorEnumByException(httpException);
String errorMessage = httpException.getResponseBodyAsString();
dataResponse = new DataResponse(errorMessage, error, DataStatusEnum.ERROR);

return dataResponse;
} catch (HttpServerErrorException ex) {
HttpStatusCodeException httpException = (HttpStatusCodeException) ex;
DataErrorEnum error = DataErrorEnum.getErrorEnumByException(httpException);
String errorMessage = httpException.getResponseBodyAsString();
dataResponse = new DataResponse(errorMessage, error, DataStatusEnum.ERROR);

return dataResponse;
} catch (RestClientException ex) {
// if it comes here, then it means some of the servers are down so adding it into block list
ShardMappings.blockHost(hostname);
}
}

if (ClientUtils.isEmpty(hostnames)) {
dataResponse = new DataResponse(null, DataErrorEnum.PERT_ERROR, DataStatusEnum.ERROR);
} else if (response == null) { // either all the servers are down or all the servers were in block list
dataResponse = new DataResponse(null, DataErrorEnum.SERVICE_UNAVAILABLE, DataStatusEnum.ERROR);
}

return dataResponse;
}
}

我的阻止列表每 1 分钟从另一个后台线程更新一次。如果任何服务器关闭并且没有响应,那么我需要使用它来阻止该服务器 -

ShardMappings.blockHost(hostname);

为了检查任何服务器是否在阻止列表中,我使用它 -

ShardMappings.isBlockHost(hostname);

如果服务器关闭或在阻止列表中,我将返回 SERVICE_UNAVAILABLE,基于 response == null 检查,不确定是否方法是否正确。

我想我根本没有遵循单一职责原则。谁能在这里举个例子,什么是使用 SRP 原则的最佳方式。

经过深思熟虑,我能够像下面给出的那样提取主机类,但不确定在我的上面使用它的最佳方法是什么 DataExecutorTask 类。

public class Hosts {

private final LinkedList<String> hostsnames = new LinkedList<String>();

public Hosts(final List<String> hosts) {
checkNotNull(hosts, "hosts cannot be null");
this.hostsnames.addAll(hosts);
}

public Optional<String> getNextAvailableHostname() {
while (!hostsnames.isEmpty()) {
String firstHostname = hostsnames.removeFirst();
if (!ClientUtils.isEmpty(firstHostname) && !ShardMappings.isBlockHost(firstHostname)) {
return Optional.of(firstHostname);
}
}
return Optional.absent();
}

public boolean isEmpty() {
return hostsnames.isEmpty();
}
}

最佳答案

您的担忧是有道理的。首先,我们来看看原始数据执行器是做什么的:

First, it is getting list of hostnames
Next, it loops through every hostnames that do the following things:
It checks whether the hostname is valid to send request.
If not valid: skip.
Else continue.
Generate the URL based on hostname
Send the request
Translate the request response to domain response
Handle exceptions
If the hostnames is empty, generate an empty response
Return response

现在,我们可以做些什么来遵循 SRP?正如我所看到的,我们可以将这些操作分组到一些组中。我可以看到的是,这些操作可以分为:

HostnameValidator:        checks whether the hostname is valid to send request
--------------
HostnameRequestSender: Generate the URL
Send the request
--------------
HttpToDataResponse: Translate the request response to domain response
--------------
HostnameExceptionHandler: Handle exceptions

也就是说,一种解耦您的操作并遵循 SRP 的方法。还有其他方法,例如简化您的操作:

First, it is getting list of hostnames
If the hostnames is empty, generate an empty response
Next, it loops through every hostnames that do the following things:
It checks whether the hostname is valid to send request
If not valid: remove hostname
Else: Generate the URL based on hostname
Next, it loops through every valid hostnames that do the following things:
Send the request
Translate the request response to domain response
Handle exceptions
Return response

那么也可以拆分为:

HostnameValidator:        checks whether the hostname is valid to send request
--------------
ValidHostnameData: Getting list of hostnames
Loops through every hostnames that do the following things:
Checks whether the hostname is valid to send request
If not valid: remove hostname
Else: Generate the URL based on hostname
--------------
HostnameRequestSender: Send the request
--------------
HttpToDataResponse: Translate the request response to domain response
--------------
HostnameExceptionHandler: Handle exceptions

当然还有其他方法可以做到。我将实现细节留空,因为有很多实现方法。

关于java - 如何在我的 HttpClient 执行程序中遵循单一职责原则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29742523/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com