设计模式-策略模式升级(服务定位器模式)
设计模式-策略模式(服务定位器模式)
前言:
正文开始前先抛出一个问题,项目开发中如果让你设计支付模块,目前有支付宝、微信、各大银行的部分,你会如何设计支付这块的代码?在调用的客户端一般都是用if else
去做判断,比如类型等于ALIPAY,我就用支付宝的实现逻辑处理,那如果新加一种支付方式,是不是调用的客户端还要修改呢?这显然太耦合了,本文就介绍一种方法(策略模式的升级版本),服务定位模式Service Locator Pattern
来解决,它帮助我们消除紧耦合实现及其依赖性,并提出将服务与其具体类解耦。
应用Service Locator Pattern
一、服务定位器
让我们定义我们的服务定位器接口PayParserFactory, 它有一个接受内容类型参数并返回PayService的方法。
import org.springframework.stereotype.Component; /** * @author dongliang7 * @projectName * @ClassName PayParserFactory.java * @description: 支付服务定位器工厂接口 * @createTime 2023年02月06日 15:01:00 */ @Component public interface PayParserFactory { /** * 服务定位器 * @param payType 支付类型 * @return 返回具体的支付处理实现类 */ PayService getPayParser(String payType); }
二、配置ServiceLocatorFactoryBean
我们配置ServiceLocatorFactoryBean使用PayParserFactory作为服务定位器接口,PayParserFactory这个接口不需要写实现类。
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.ServiceLocatorFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author dongliang7 * @projectName * @ClassName PayParserConfig.java * @description: 支付解析器配置 * @createTime 2023年02月06日 15:06:00 */ @Configuration public class PayParserConfig { /** * 初始化 payParserFactory bean * @return */ @Bean("payParserFactory") public FactoryBean serviceLocatorFactoryBean() { ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean(); // 设置服务定位接口 factoryBean.setServiceLocatorInterface(PayParserFactory.class); return factoryBean; } }
三、定义一个支付的接口
/** * @author dongliang7 * @projectName * @ClassName PayParser.java * @description: 支付服务接口 * @createTime 2023年02月06日 15:02:00 */ public interface PayService { //支付接口 boolean pay(String orderId); }
四、根据不同类型处理Bean
设置解析器Bean的名称为类型名称,方便服务定位
- 支付宝支付:
import org.springframework.stereotype.Component; /** * @author dongliang7 * @projectName * @ClassName AliPay.java * @description: 支付宝支付实现层 * @createTime 2023年02月06日 15:09:00 */ @Component("AliPay") public class AliPayService implements PayService{ @Override public boolean pay(String orderId) { System.out.println("支付宝支付-----------------------"); return true; } }
- 微信支付:
import org.springframework.stereotype.Component; /** * @author dongliang7 * @projectName * @ClassName WxPayService.java * @description: 微信支付实现层 * @createTime 2023年02月06日 15:17:00 */ @Component("WxPay") public class WxPayService implements PayService{ @Override public boolean pay(String orderId) { System.out.println("微信支付-----------------------"); return true; } }
五、创建一个controller层
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * @author dongliang7 * @projectName * @ClassName PayController.java * @description: 支付模块控制层 * @createTime 2023年02月06日 15:20:00 */ @RestController @RequestMapping("/pay") public class PayController { @Autowired private PayParserFactory payParserFactory; @PostMapping("/orderPay") public boolean orderPay(@RequestParam String payType) { // 关键点,直接根据类型获取 boolean result = payParserFactory.getPayParser(payType).pay("P202302061524001"); return result; } }
总结:
Spring 的ServiceLocatorFactoryBean实现了 FactoryBean接口,创建了Service Factory服务工厂Bean。我们通过使用服务定位器模式实现了一种扩展 Spring 控制反转的方法。它帮助我们解决了依赖注入未提供最佳解决方案的用例。也就是说,依赖注入仍然是首选,并且在大多数情况下不应使用服务定位器来替代依赖注入。