一、简述

项目开发中,我们通常会遇到很多的if-else条件分枝判断场景。阿里巴巴开发手册中规定:超过3层的if-else时,需要使用卫语句和策略模式,或者工程模式进行优化。

二、策略模式

设计模式:策略模式 工厂模式解决if-else - 图1

1、含义

策略模式通常是由 选择策略环境(调用类)、策略接口类、策略接口多种实现类组成。
客户端在选择策略环境中,通常是通过传递不同的类型参数(serverType)来实例化不同的策略接口,进而通过不同的策略接口来实现业务逻辑。
也就是说:根据不同的场景、通过类型参数获取到不同的处理策略。

2、优缺点

1、优点

1、优化if-else/switch casr语句,使得代码更加简洁。
2、通常只需要增加相应的策略实现类、以及维护一个策略类型枚举即可,遵循了开闭原则。

2、缺点

使用场景过多,还是会产生过多的策略类、一定程度上增加了理解成本。

3、应用举例

  1. 现在有三种支付模式需求,一种是微信支付、一种是支付宝支付、一种是银联支付。

1、传统模式

传统的实现思想是在接口中通过if-else、switch case语句来进行不同场景的判断。如果场景模式过多,则会产生大量的if-else,或者很长的switch case语句块

  1. /**
  2. * 支付接口
  3. * @Parma type 支付类型
  4. */
  5. public Result pay(String type){
  6. if(type == '微信支付'){
  7. // 业务逻辑
  8. return Result;
  9. }
  10. if(type == '支付宝支付'){
  11. // 业务逻辑
  12. return Result;
  13. }
  14. if(type == '银联支付'){
  15. // 业务逻辑
  16. return Result;
  17. }
  18. }

2、策略模式

1、创建Service接口:通常指的是我们需要提供的策略服务接口,这里的Service则是PayService接口。

  1. @Service
  2. public interface PayService(){
  3. // 通用支付方法
  4. Result payMethod();
  5. }

2、创建不同的策略服务子类、实现上传策略服务接口Service、并分别实现Service中的payMethod()方法

  1. @Service
  2. public class WeixinPayServiceImpl implements PayService{
  3. @Override
  4. public Result payMethod(){
  5. // 微信支付业务逻辑
  6. return Result;
  7. }
  8. }
  9. @Service
  10. public class ZhifupaoPayServiceImpl implements PayService{
  11. @Override
  12. public Result payMethod(){
  13. // 支付宝业务逻辑
  14. return Result;
  15. }
  16. }
  17. @Service
  18. public class YinlianPayServiceImpl implements PayService{
  19. @Override
  20. public Result payMethod(){
  21. // 银联支付业务逻辑
  22. return Result;
  23. }
  24. }

3、创建Controller接口进行测试,这里的测试接口其实就是策略模式的Choose类

  1. @RestController
  2. public Result pay(String type){
  3. PayService payService = null;
  4. if(type == '微信支付'){
  5. payService = new WeixinPayServiceImpl();
  6. }
  7. if(type == '支付宝支付'){
  8. payService = new ZhifubaoPayServiceImpl();
  9. }
  10. if(type == '银联支付'){
  11. payService = new YinlianPayServiceImpl();
  12. }
  13. return payService.payMethod();
  14. }

4、总结
通过上述三种不同的支付方式举例,我们可以看出,即使我们脱离了传统模式下的实现方式,但在Choose选择类中(Controller)中我们还是间接的使用了if-else语句块来进行不同的业务逻辑实现。

三、工厂模式

1、含义

工厂模式就是指一种通过工厂来创建对象的最佳方法。
通常使用一个Factory工厂类来管理创建多种不同的实现类。当我们需要使用不同的对象时,只需要在工厂类中进行获取即可。而不需要我们再次进行创建。
工厂模式通常包含:简单工厂模式、工厂方法模式、抽象工厂模式。

2、简单工厂模式

20201012170028309.png
我们通过手机生产厂商来进行举例子。
1、创建手机接口

  1. @Service
  2. public interface PhoneService{
  3. void make();
  4. }

2、创建多种手机生产厂商实现类来实现上述生产手机的接口Service

  1. @Service
  2. public class XiaomiPhoneServiceImpl implements PhoneService{
  3. @Override
  4. void make(){
  5. // 小米生产手机
  6. }
  7. }
  8. @Service
  9. public class PingguoPhoneServiceImpl implements PhoneService{
  10. @Override
  11. void make(){
  12. // 苹果生产手机
  13. }
  14. }
  15. @Service
  16. public class HUAWEIPhoneServiceImpl implements PhoneService{
  17. @Override
  18. void make(){
  19. // 华为生产手机
  20. }
  21. }

3、创建生产手机工厂类Factory

  1. public class PhoneMakeFactory{
  2. public PhoneService makePhone(String type){
  3. if(type == '小米生产手机'){
  4. return new XiaomiPhoneServiceImpl();
  5. }
  6. if(type == '苹果生产手机'){
  7. return new PingguoPhoneServiceImpl();
  8. }
  9. if(type == '华为生产手机'){
  10. return new HUAWEIPhoneServiceimpl();
  11. }
  12. return null;
  13. }
  14. }

4、创建测试类

  1. @RestController
  2. public Class phoneController{
  3. public phone getPhone(String type){
  4. PhoneFactory factory = new PhoneFactory();
  5. PhoneService service = factory.makePhone(type);
  6. return service.make();
  7. }
  8. }

3、工厂方法模式 4、抽象工厂模式

四、策略模式+工厂模式业务

1、业务需求

一个系统,具有笔记点赞模块、评论点赞、评论回复点赞三种模块需要进行实现。传统做法是直接使用if-else、switch case进行逻辑判断后再进行具体的业务实现。
优化1:使用策略模式
直接使用策略模式虽然一定程度上避免了具体的if-else直接判断,但是策略模式在进行策略分发的
时候还是会间接的使用到if-else或者switch。
优化2:策略模式+工厂模式

1、通用数据Dto

  1. @ApiModel("点赞/取消点赞Dto参数封装")
  2. @Data
  3. public class LikeDto {
  4. @ApiModelProperty("用户id")
  5. @NotEmpty(message = "用户id不能为空")
  6. private String userId;
  7. @ApiModelProperty("被点赞id")
  8. @NotNull(message = "目标id不能为空")
  9. private Integer targetId;
  10. @ApiModelProperty("点赞类型(1:笔记点赞, 2:评论点赞,3:评论回复点赞)")
  11. @NotNull(message = "点赞类型不能为空")
  12. private Integer likeType;
  13. }

2、创建点赞策略工厂枚举类

  1. public enum LikeFactoryEnum {
  2. /** 点赞类型枚举值 */
  3. NOTE_LIKE(1, "笔记点赞"),
  4. COMMENT_LIKE(2, "评论点赞"),
  5. COMMENT_REPLY_LIKE(3, "评论回复点赞");
  6. /** 枚举属性 */
  7. private Integer type;
  8. private String value;
  9. LikeFactoryEnum(Integer type, String value){
  10. this.type = type;
  11. this.value = value;
  12. }
  13. public Integer getType(){
  14. return this.type;
  15. }
  16. public String getValue(){
  17. return this.value;
  18. }
  19. }

3、创建LikeService点赞策略服务

该接口中只提供一个更新点赞的方法,需要通过子类进行实现该类、进行重写该方法即可。

  1. @Service
  2. public interface LikeService {
  3. /**
  4. * 点赞/取消点赞接口
  5. * @param likeDto 点赞/取消点赞参数Dto
  6. * @return
  7. */
  8. Result updateLike(LikeDto likeDto);
  9. }

4、创建多子类实现LikeService接口

  1. @Service
  2. @Slf4j
  3. public class NoteLikeServiceImpl implements LikeService, InitializingBean {
  4. /**
  5. * 实现LikeService接口中的点赞通用方法
  6. */
  7. @Override
  8. public Result updateLike(LikeDto likeDto) {
  9. System.out.println(likeDto.toString());
  10. return Result.success();
  11. }
  12. /**
  13. * 实现了InitializingBean接口,通过 type - serviceImpl注入到工厂Map容器中
  14. */
  15. @Override
  16. public void afterPropertiesSet() throws Exception {
  17. LikeServerFactory.register(LikeFactoryEnum.NOTE_LIKE.getType(), this);
  18. }
  19. }
  20. @Service
  21. @Slf4j
  22. public class CommentLikeServiceImpl implements LikeService, InitializingBean {
  23. /**
  24. * 实现LikeService接口中的点赞通用方法
  25. */
  26. @Override
  27. public Result updateLike(LikeDto likeDto) {
  28. System.out.println(likeDto.toString());
  29. return Result.success();
  30. }
  31. /**
  32. * 实现了InitializingBean接口,通过 type - serviceImpl注入到工厂Map容器中
  33. */
  34. @Override
  35. public void afterPropertiesSet() throws Exception {
  36. LikeServerFactory.register(LikeFactoryEnum.COMMENT_LIKE.getType(), this);
  37. }
  38. }

5、创建Factory工厂类

  1. @Service
  2. @Slf4j
  3. public class LikeServerFactory {
  4. /**
  5. * LikeService接口的子类ConcurrentHashMap集合
  6. */
  7. private static Map<Integer, LikeService> serviceMap = new ConcurrentHashMap<Integer, LikeService>();
  8. /**
  9. * 根据点赞类型获取到不同的点赞服务实现类
  10. * @param type 点赞类型
  11. * @return 点赞Service实现类
  12. */
  13. public static LikeService getLikeServiceByType(Integer type){
  14. return serviceMap.get(type);
  15. }
  16. /**
  17. * 传入类型、Service实现类,将其注入到ConcurrentHashMap容器中
  18. * @param type 类型
  19. * @param likeService 实现类
  20. */
  21. public static void register(Integer type, LikeService likeService){
  22. Assert.notNull(type, "type can't be null!");
  23. serviceMap.put(type, likeService);
  24. }
  25. }

6、创建Api接口

  1. @Api(tags = "点赞模块")
  2. @RestController
  3. @RequestMapping("/like")
  4. public class LikeController {
  5. /**
  6. * 根据不同点赞类型对目标id进行点赞/取消点赞
  7. * @param likeDto 点赞Dto参数封装
  8. * @return 操作状态
  9. */
  10. @PostMapping("/updateLike")
  11. @ApiOperation(value = "点赞/取消点赞", notes = "点赞类型(1:笔记点赞,2:评论点赞,3:评论回复点赞)")
  12. public Result updateLike(@Valid @RequestBody LikeDto likeDto){
  13. Integer type = likeDto.getLikeType();
  14. // 从工厂中获取实体类
  15. LikeService likeService = LikeServerFactory.getLikeServiceByType(type);
  16. return likeService.updateLike(likeDto);
  17. }
  18. }

五、总结

上述应用举例中,我们使用了策略模式+工厂模式进行了具有实际业务需求的思想实现。
总体逻辑如下:
Api:该Controller层中调用了Factory工厂类来获取具体的策略接口实现类
Factory:该工厂类中提供了ConcurrentHashMap容器来存储所有的策略服务实现子类
getLikeServiceByType(Integer type):该方法通过type来获取不同的策略服务子类
register(Integer type, LikeService likeService):该方法通过type-service来将策略服务子类注入到
Map容器中
LikeService:该接口中提供通用点赞方法,需要使用具体的子类来实现并重写
ServiceImpl:不同的策略服务实现子类、包含具体业务方法、注入Factory方法
image.png
这种模式下,维护时,我们只需要添加相应的策略服务子类、以及维护一个策略服务类型枚举即可。