一、简述
项目开发中,我们通常会遇到很多的if-else条件分枝判断场景。阿里巴巴开发手册中规定:超过3层的if-else时,需要使用卫语句和策略模式,或者工程模式进行优化。
二、策略模式
1、含义
策略模式通常是由 选择策略环境(调用类)、策略接口类、策略接口多种实现类组成。
客户端在选择策略环境中,通常是通过传递不同的类型参数(serverType)来实例化不同的策略接口,进而通过不同的策略接口来实现业务逻辑。
也就是说:根据不同的场景、通过类型参数获取到不同的处理策略。
2、优缺点
1、优点
1、优化if-else/switch casr语句,使得代码更加简洁。
2、通常只需要增加相应的策略实现类、以及维护一个策略类型枚举即可,遵循了开闭原则。
2、缺点
使用场景过多,还是会产生过多的策略类、一定程度上增加了理解成本。
3、应用举例
现在有三种支付模式需求,一种是微信支付、一种是支付宝支付、一种是银联支付。
1、传统模式
传统的实现思想是在接口中通过if-else、switch case语句来进行不同场景的判断。如果场景模式过多,则会产生大量的if-else,或者很长的switch case语句块
/*** 支付接口* @Parma type 支付类型*/public Result pay(String type){if(type == '微信支付'){// 业务逻辑return Result;}if(type == '支付宝支付'){// 业务逻辑return Result;}if(type == '银联支付'){// 业务逻辑return Result;}}
2、策略模式
1、创建Service接口:通常指的是我们需要提供的策略服务接口,这里的Service则是PayService接口。
@Servicepublic interface PayService(){// 通用支付方法Result payMethod();}
2、创建不同的策略服务子类、实现上传策略服务接口Service、并分别实现Service中的payMethod()方法
@Servicepublic class WeixinPayServiceImpl implements PayService{@Overridepublic Result payMethod(){// 微信支付业务逻辑return Result;}}@Servicepublic class ZhifupaoPayServiceImpl implements PayService{@Overridepublic Result payMethod(){// 支付宝业务逻辑return Result;}}@Servicepublic class YinlianPayServiceImpl implements PayService{@Overridepublic Result payMethod(){// 银联支付业务逻辑return Result;}}
3、创建Controller接口进行测试,这里的测试接口其实就是策略模式的Choose类
@RestControllerpublic Result pay(String type){PayService payService = null;if(type == '微信支付'){payService = new WeixinPayServiceImpl();}if(type == '支付宝支付'){payService = new ZhifubaoPayServiceImpl();}if(type == '银联支付'){payService = new YinlianPayServiceImpl();}return payService.payMethod();}
4、总结
通过上述三种不同的支付方式举例,我们可以看出,即使我们脱离了传统模式下的实现方式,但在Choose选择类中(Controller)中我们还是间接的使用了if-else语句块来进行不同的业务逻辑实现。
三、工厂模式
1、含义
工厂模式就是指一种通过工厂来创建对象的最佳方法。
通常使用一个Factory工厂类来管理创建多种不同的实现类。当我们需要使用不同的对象时,只需要在工厂类中进行获取即可。而不需要我们再次进行创建。
工厂模式通常包含:简单工厂模式、工厂方法模式、抽象工厂模式。
2、简单工厂模式

我们通过手机生产厂商来进行举例子。
1、创建手机接口
@Servicepublic interface PhoneService{void make();}
2、创建多种手机生产厂商实现类来实现上述生产手机的接口Service
@Servicepublic class XiaomiPhoneServiceImpl implements PhoneService{@Overridevoid make(){// 小米生产手机}}@Servicepublic class PingguoPhoneServiceImpl implements PhoneService{@Overridevoid make(){// 苹果生产手机}}@Servicepublic class HUAWEIPhoneServiceImpl implements PhoneService{@Overridevoid make(){// 华为生产手机}}
3、创建生产手机工厂类Factory
public class PhoneMakeFactory{public PhoneService makePhone(String type){if(type == '小米生产手机'){return new XiaomiPhoneServiceImpl();}if(type == '苹果生产手机'){return new PingguoPhoneServiceImpl();}if(type == '华为生产手机'){return new HUAWEIPhoneServiceimpl();}return null;}}
4、创建测试类
@RestControllerpublic Class phoneController{public phone getPhone(String type){PhoneFactory factory = new PhoneFactory();PhoneService service = factory.makePhone(type);return service.make();}}
3、工厂方法模式 4、抽象工厂模式
四、策略模式+工厂模式业务
1、业务需求
一个系统,具有笔记点赞模块、评论点赞、评论回复点赞三种模块需要进行实现。传统做法是直接使用if-else、switch case进行逻辑判断后再进行具体的业务实现。
优化1:使用策略模式
直接使用策略模式虽然一定程度上避免了具体的if-else直接判断,但是策略模式在进行策略分发的
时候还是会间接的使用到if-else或者switch。
优化2:策略模式+工厂模式
1、通用数据Dto
@ApiModel("点赞/取消点赞Dto参数封装")@Datapublic class LikeDto {@ApiModelProperty("用户id")@NotEmpty(message = "用户id不能为空")private String userId;@ApiModelProperty("被点赞id")@NotNull(message = "目标id不能为空")private Integer targetId;@ApiModelProperty("点赞类型(1:笔记点赞, 2:评论点赞,3:评论回复点赞)")@NotNull(message = "点赞类型不能为空")private Integer likeType;}
2、创建点赞策略工厂枚举类
public enum LikeFactoryEnum {/** 点赞类型枚举值 */NOTE_LIKE(1, "笔记点赞"),COMMENT_LIKE(2, "评论点赞"),COMMENT_REPLY_LIKE(3, "评论回复点赞");/** 枚举属性 */private Integer type;private String value;LikeFactoryEnum(Integer type, String value){this.type = type;this.value = value;}public Integer getType(){return this.type;}public String getValue(){return this.value;}}
3、创建LikeService点赞策略服务
该接口中只提供一个更新点赞的方法,需要通过子类进行实现该类、进行重写该方法即可。
@Servicepublic interface LikeService {/*** 点赞/取消点赞接口* @param likeDto 点赞/取消点赞参数Dto* @return*/Result updateLike(LikeDto likeDto);}
4、创建多子类实现LikeService接口
@Service@Slf4jpublic class NoteLikeServiceImpl implements LikeService, InitializingBean {/*** 实现LikeService接口中的点赞通用方法*/@Overridepublic Result updateLike(LikeDto likeDto) {System.out.println(likeDto.toString());return Result.success();}/*** 实现了InitializingBean接口,通过 type - serviceImpl注入到工厂Map容器中*/@Overridepublic void afterPropertiesSet() throws Exception {LikeServerFactory.register(LikeFactoryEnum.NOTE_LIKE.getType(), this);}}@Service@Slf4jpublic class CommentLikeServiceImpl implements LikeService, InitializingBean {/*** 实现LikeService接口中的点赞通用方法*/@Overridepublic Result updateLike(LikeDto likeDto) {System.out.println(likeDto.toString());return Result.success();}/*** 实现了InitializingBean接口,通过 type - serviceImpl注入到工厂Map容器中*/@Overridepublic void afterPropertiesSet() throws Exception {LikeServerFactory.register(LikeFactoryEnum.COMMENT_LIKE.getType(), this);}}
5、创建Factory工厂类
@Service@Slf4jpublic class LikeServerFactory {/*** LikeService接口的子类ConcurrentHashMap集合*/private static Map<Integer, LikeService> serviceMap = new ConcurrentHashMap<Integer, LikeService>();/*** 根据点赞类型获取到不同的点赞服务实现类* @param type 点赞类型* @return 点赞Service实现类*/public static LikeService getLikeServiceByType(Integer type){return serviceMap.get(type);}/*** 传入类型、Service实现类,将其注入到ConcurrentHashMap容器中* @param type 类型* @param likeService 实现类*/public static void register(Integer type, LikeService likeService){Assert.notNull(type, "type can't be null!");serviceMap.put(type, likeService);}}
6、创建Api接口
@Api(tags = "点赞模块")@RestController@RequestMapping("/like")public class LikeController {/*** 根据不同点赞类型对目标id进行点赞/取消点赞* @param likeDto 点赞Dto参数封装* @return 操作状态*/@PostMapping("/updateLike")@ApiOperation(value = "点赞/取消点赞", notes = "点赞类型(1:笔记点赞,2:评论点赞,3:评论回复点赞)")public Result updateLike(@Valid @RequestBody LikeDto likeDto){Integer type = likeDto.getLikeType();// 从工厂中获取实体类LikeService likeService = LikeServerFactory.getLikeServiceByType(type);return likeService.updateLike(likeDto);}}
五、总结
上述应用举例中,我们使用了策略模式+工厂模式进行了具有实际业务需求的思想实现。
总体逻辑如下:
Api:该Controller层中调用了Factory工厂类来获取具体的策略接口实现类
Factory:该工厂类中提供了ConcurrentHashMap容器来存储所有的策略服务实现子类
getLikeServiceByType(Integer type):该方法通过type来获取不同的策略服务子类
register(Integer type, LikeService likeService):该方法通过type-service来将策略服务子类注入到
Map容器中
LikeService:该接口中提供通用点赞方法,需要使用具体的子类来实现并重写
ServiceImpl:不同的策略服务实现子类、包含具体业务方法、注入Factory方法
这种模式下,维护时,我们只需要添加相应的策略服务子类、以及维护一个策略服务类型枚举即可。
