这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战
一、基本介绍
定义
外观模式是一种结构型设计模式,隐藏了系统的复杂性, 能为程序库、 框架或其他复杂类提供一个简单的接口。
作用
主要解决的是降低调用方的使用接口的复杂逻辑组合。这样调用方与实际的接口提供方提供方提供了一个中间层,用于包装逻辑提供API接口。
应用场景
-
如果需要将子系统组织为多层结构, 可以使用外观。
-
可以用在中间件层,对服务中的通用性复杂逻辑进行中间件层包装,让使用方可以只关心业务开发。
优缺点
-
可以让自己的代码独立于复杂子系统。
-
外观可能成为与程序中所有类都耦合的上帝对象
画外(自己的话QAQ)
这么说,其实我们平时开发的时候也是有注意到这个的,比如一个下订单功能,里面又细分有生成订单订单、删除购物车、增加积分等等操作,但是我们对外暴露的,只会是一个 提交订单服务,调用该服务的人,只需要关心如何调用就行,而不需要关心下单的一系列内部逻辑。
实例
下面举的例子是 外观模式应用在中间层的实例
需求:比如系统有一些接口:查看店铺信息接口、查看商品信息接口、查看个人信息接口等等,我们需要做个统计,即调用了这些接口的次数统计,如果一个个接口去处理,有略显繁琐,并且随着需求的增加,CV工作量还会加大,代码重复量多也不雅观(不够炫!QAQ)
处理:所以考虑自定义个注解,在有需要的接口加上注解,然后统计。
二、实践
(1)新建个测试Controller,只有简单的测试接口
@RestController
@RequestMapping("/facade")
public class FacadeController {
@GetMapping("/")
public String text(){
return "外观模式实践:自定义注解";
}
@GetMapping("/getShopInfo")
public String getShopInfo(String shop_id){
return "查看店铺信息,店铺ID:"+shop_id;
}
@GetMapping("/getProductInfo")
public String getProductInfo(String product_id){
return "查看商品信息,商品ID:"+product_id;
}
@GetMapping("/getPersonInfo")
public String getPersonInfo(String person_id){
return "查看个人信息,个人ID"+person_id;
}
}
(2)自定义注解 CountInterface
/**
* @author 勤任风
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CountInterface {
String key() default "";
}
(3)切面实现 注解的逻辑
/**
* @author 勤任风
* @date 2021-08-07 14:08
*/
@Aspect
@Component
@Slf4j
public class CountInterfacePoint {
@Autowired
RedisTemplate redisTemplate;
@Pointcut("@annotation(com.example.demo.design.facade.annotation.CountInterface)")
public void aopPoint() {
}
@Around("aopPoint()")
public Object doCount(ProceedingJoinPoint jp) throws Throwable {
log.info("进来注解了!");
//获取内容
Method method = getMethod(jp);
CountInterface countInterface = method.getAnnotation(CountInterface.class);
//获取注解字段key的值
String key = countInterface.key();
//获取方法参数的值
Object[] params = jp.getArgs();
// 获取第一个参数的值,并做为redis的key补充,
String temp="";
if(params!=null){
temp=params[0].toString();
}
// 例如:用key+参数值作为redis的键,如:shop01、shop02、person01,然后值自增+1
RedisAtomicLong entityIdCounter = new RedisAtomicLong(key+temp, redisTemplate.getConnectionFactory());
entityIdCounter.incrementAndGet();
//继续执行 注解之后的逻辑
return jp.proceed();
}
private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
Signature sig = jp.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
return getClass(jp).getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
}
private Class<? extends Object> getClass(JoinPoint jp) throws NoSuchMethodException {
return jp.getTarget().getClass();
}
}
(4)在需要统计的接口,加上@CountInterface注解,内容key自己定,结果如下:
(5)测试,调用获取ID为12的店铺信息接口,连续调用n次
(6)可以看到Redis里面已经有了自增的数据