JAVA设计模式——策略模式
策略模式是一种行为型设计模式,它允许在运行时选择算法的行为。它定义了一系列算法,将每个算法封装起来并使它们可以相互替换。策略模式使算法的变化独立于使用算法的客户端。
在策略模式中,我们有一个上下文对象,该对象包含一个指向策略对象的引用。策略对象实现了一个公共接口,该接口定义了所有策略对象都必须实现的方法。上下文对象在运行时可以将策略对象替换为另一个策略对象,从而改变其行为。
以下是策略模式的一些关键要素:
-
上下文(Context):包含一个指向策略对象的引用。
-
策略(Strategy):定义了所有策略对象都必须实现的方法。
-
具体策略(Concrete Strategy):实现了策略接口的具体算法。
下面是一个简单的示例,说明如何使用策略模式:
// 策略接口
interface Strategy {
int doOperation(int num1, int num2);
}
// 具体策略1
class OperationAdd implements Strategy {
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
// 具体策略2
class OperationSubtract implements Strategy {
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
// 具体策略3
class OperationMultiply implements Strategy {
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
// 上下文
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
// 测试
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
在上面的示例中,我们定义了一个策略接口 Strategy
,并实现了三个具体策略类 OperationAdd
、OperationSubtract
和 OperationMultiply
。我们还定义了一个上下文类 Context
,它包含一个指向策略对象的引用,并提供了一个执行策略的方法 executeStrategy
。在测试代码中,我们创建了一个上下文对象,并使用不同的策略对象来执行不同的算法。
项目实践:使用策略模式,实现接口回调时支持多种回调方式(http、feign调用等)
第一步:定义回调策略接口
import java.util.List;
import java.util.Map;
/**
* @since 2023/7/18
*/
public interface CallbackStrategy {
/**
* 获取支持的回调类型
*
* @return
*/
String getSupportCallbackType();
/**
* 执行回调
*/
Map<String, Object> executeCallback(String callbackUrl, CommonReq<List<Map<String, Object>>> commonReq);
}
第二步:定义回调抽象类实现回调策略接口:
import cn.hutool.core.text.CharSequenceUtil;
import com.*.CallbackConstants;
import com.*.AbstractAccessor;
import com.*.Logger;
import com.*.LoggerFactory;
import com.*.CommonReq;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @since 2023/7/18
*/
public abstract class AbstractCallbackStrategy implements CallbackStrategy {
private static final Logger log = LoggerFactory.getLogger(AbstractCallbackStrategy.class);
/**
* accessor
*
* @return
*/
protected abstract AbstractAccessor getAccessor();
/**
* 执行回调
*/
@Override
public Map<String, Object> executeCallback(String callbackUrl, CommonReq<List<Map<String, Object>>> commonReq) {
Map map = new HashMap();
try {
map = getAccessor().defaultPostForValue(callbackUrl, commonReq, Map.class);
} catch (Exception e) {
map.put(CallbackConstants.CODE, CallbackConstants.ERROR_CODE);
map.put(CallbackConstants.MSG, e.getMessage());
log.error("服务调用异常,异常信息如下:{}", e);
}
return map;
}
}
第三步:定义feign调用回调策略类
import com.*.CallbackTypeEnum;
import com.*.utils.AbstractAccessor;
import com.*.FeignAccessor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* @since 2023/7/18
*/
@Component
@RequiredArgsConstructor
public class FeignCallbackStrategy extends AbstractCallbackStrategy implements CallbackStrategy {
private final FeignAccessor feignAccessor;
@Override
public String getSupportCallbackType() {
return CallbackTypeEnum.FEIGN.getCode();
}
@Override
protected AbstractAccessor getAccessor() {
return feignAccessor;
}
}
第四步:定义 http回调策略类
import com.*.CallbackTypeEnum;
import com.*.AbstractAccessor;
import com.*.HttpAccessor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* @since 2023/7/18
*/
@Component
@RequiredArgsConstructor
public class HttpCallbackStrategy extends AbstractCallbackStrategy implements CallbackStrategy {
private final HttpAccessor httpAccessor;
@Override
public String getSupportCallbackType() {
return CallbackTypeEnum.HTTP.getCode();
}
@Override
protected AbstractAccessor getAccessor() {
return httpAccessor;
}
}
第五步:定义访问方式抽象类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
/**
* @since 2023/7/18
*/
public abstract class AbstractAccessor {
private static final Logger LOG = LoggerFactory.getLogger(AbstractAccessor.class);
/**
* <pre>
* 远程调用微服务,返回ApiResponse对象
* 默认的数据请求格式为application/json
* </pre>
*
* @param url 微服务地址
* @param param 请求参数
* @param clazz 返回类型
*/
public <T> T defaultPostForValue(String url, Object param, Class<T> clazz) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(param, headers);
return postForValue(url, entity, clazz);
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse对象
* 默认的数据请求格式为application/json
* </pre>
*
* @param url 微服务地址
* @param param 请求参数
* @param clazz 返回类型
*/
public <T> ResponseEntity<T> defaultPostForEntity(String url, Object param, Class<T> clazz) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(param, headers);
return postForEntity(url, entity, clazz);
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse后的Data值对象
* </pre>
*
* @param url 微服务地址
* @param entity 请求实体
* @param clazz 返回类型
*/
public <T, R> T postForValue(String url, HttpEntity<R> entity, Class<T> clazz) {
ResponseEntity<T> responseEntity = this.postForEntity(url, entity, clazz);
return responseEntity.getBody();
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse后的Data值对象
* </pre>
*
* @param url 微服务地址
* @param entity 请求实体
* @param clazz 返回类型
*/
public <T, R> ResponseEntity<T> postForEntity(String url, HttpEntity<R> entity, Class<T> clazz) {
if (LOG.isDebugEnabled()) {
LOG.debug("远程地址:{},请求参数:{}", url, JSON.toJSONString(entity.getBody(),
SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames));
}
ResponseEntity<T> responseEntity = getRestTemplate().exchange(url, HttpMethod.POST, entity, clazz);
if (LOG.isDebugEnabled()) {
LOG.debug("远程地址:{},返回结果:{}", url, JSON.toJSONString(responseEntity.getBody(),
SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames));
}
return responseEntity;
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse对象
* 默认的数据请求格式为application/json
* </pre>
*
* @param url 微服务地址
* @param param 请求参数
* @param clazz 返回类型
*/
public <T> T defaultGetForValue(String url, Object param, Class<T> clazz) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(param, headers);
return getForValue(url, entity, clazz);
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse对象
* 默认的数据请求格式为application/json
* </pre>
*
* @param url 微服务地址
* @param param 请求参数
* @param clazz 返回类型
*/
public <T> ResponseEntity<T> defaultGetForEntity(String url, Object param, Class<T> clazz) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(param, headers);
return getForEntity(url, entity, clazz);
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse后的Data值对象
* </pre>
*
* @param url 微服务地址
* @param entity 请求实体
* @param clazz 返回类型
*/
public <T, R> T getForValue(String url, HttpEntity<R> entity, Class<T> clazz) {
ResponseEntity<T> responseEntity = this.getForEntity(url, entity, clazz);
return responseEntity.getBody();
}
/**
* <pre>
* 远程调用微服务,返回ApiResponse后的Data值对象
* </pre>
*
* @param url 微服务地址
* @param entity 请求实体
* @param clazz 返回类型
*/
public <T, R> ResponseEntity<T> getForEntity(String url, HttpEntity<R> entity, Class<T> clazz) {
if (LOG.isDebugEnabled()) {
LOG.debug("远程地址:{},请求参数:{}", url, JSON.toJSONString(entity.getBody(),
SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames));
}
ResponseEntity<T> responseEntity = getRestTemplate().exchange(url, HttpMethod.GET, entity, clazz);
if (LOG.isDebugEnabled()) {
LOG.debug("远程地址:{},返回结果:{}", url, JSON.toJSONString(responseEntity.getBody(),
SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames));
}
return responseEntity;
}
protected abstract RestTemplate getRestTemplate();
}
第六步:定义feign调用方式
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @since 2023/7/18
*/
@Component
public class FeignAccessor extends AbstractAccessor {
@Resource(name = "feignRestTemplate")
private RestTemplate feignRestTemplate;
@Override
protected RestTemplate getRestTemplate() {
return feignRestTemplate;
}
}
第七步:http调用方式
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @since 2023/7/18
*/
@Component
public class HttpAccessor extends AbstractAccessor {
@Resource(name = "httpRestTemplate")
private RestTemplate httpRestTemplate;
@Override
protected RestTemplate getRestTemplate() {
return httpRestTemplate;
}
}
第八步:接口回调
/**
* @since 2023/7/17
*/
@Service
@RequiredArgsConstructor
public class CallbackAppServiceImpl implements CallbackAppService {
private final List<CallbackStrategy> callbackStrategyList;
/**
* 回调明细操作
*
* @param batchId
* @param serialNumber
* @param interfaceCode
*/
private boolean executeCallbackDetail(Long batchId, String serialNumber, String interfaceCode) {
// 通过 interfaceCode 获取回调地址,并返回List<BaseCallbackConfigBO>
BaseCallbackConfigBO callbackConfigBO = callbackConfigDomainService.getCallbackUrlByInterfaceCode(interfaceCode);
String callbackType = callbackConfigBO.getCallbackType();
String callbackUrl = callbackConfigBO.getCallbackServiceName();
// 构造回调参数
List<Map<String, Object>> maps = boList.stream().map(obj -> {
Map<String, Object> map = new HashMap<>();
map.put("callBackCode", obj.getProcessStatus());
map.put("callBackMsg", obj.getProcessMessage());
return map;
}).collect(Collectors.toList());
CommonReq<List<Map<String, Object>>> commonReq = CommonReq.build(maps);
Map<String, Object> map = callbackStrategyList.stream().filter(obj -> callbackType.equals(obj.getSupportCallbackType())).findFirst().get().executeCallback(callbackUrl, commonReq);
return true;
}
}