一、简述
项目开发中,我们通常会遇到很多的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接口。
@Service
public interface PayService(){
// 通用支付方法
Result payMethod();
}
2、创建不同的策略服务子类、实现上传策略服务接口Service、并分别实现Service中的payMethod()方法
@Service
public class WeixinPayServiceImpl implements PayService{
@Override
public Result payMethod(){
// 微信支付业务逻辑
return Result;
}
}
@Service
public class ZhifupaoPayServiceImpl implements PayService{
@Override
public Result payMethod(){
// 支付宝业务逻辑
return Result;
}
}
@Service
public class YinlianPayServiceImpl implements PayService{
@Override
public Result payMethod(){
// 银联支付业务逻辑
return Result;
}
}
3、创建Controller接口进行测试,这里的测试接口其实就是策略模式的Choose类
@RestController
public 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、创建手机接口
@Service
public interface PhoneService{
void make();
}
2、创建多种手机生产厂商实现类来实现上述生产手机的接口Service
@Service
public class XiaomiPhoneServiceImpl implements PhoneService{
@Override
void make(){
// 小米生产手机
}
}
@Service
public class PingguoPhoneServiceImpl implements PhoneService{
@Override
void make(){
// 苹果生产手机
}
}
@Service
public class HUAWEIPhoneServiceImpl implements PhoneService{
@Override
void 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、创建测试类
@RestController
public 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参数封装")
@Data
public 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点赞策略服务
该接口中只提供一个更新点赞的方法,需要通过子类进行实现该类、进行重写该方法即可。
@Service
public interface LikeService {
/**
* 点赞/取消点赞接口
* @param likeDto 点赞/取消点赞参数Dto
* @return
*/
Result updateLike(LikeDto likeDto);
}
4、创建多子类实现LikeService接口
@Service
@Slf4j
public class NoteLikeServiceImpl implements LikeService, InitializingBean {
/**
* 实现LikeService接口中的点赞通用方法
*/
@Override
public Result updateLike(LikeDto likeDto) {
System.out.println(likeDto.toString());
return Result.success();
}
/**
* 实现了InitializingBean接口,通过 type - serviceImpl注入到工厂Map容器中
*/
@Override
public void afterPropertiesSet() throws Exception {
LikeServerFactory.register(LikeFactoryEnum.NOTE_LIKE.getType(), this);
}
}
@Service
@Slf4j
public class CommentLikeServiceImpl implements LikeService, InitializingBean {
/**
* 实现LikeService接口中的点赞通用方法
*/
@Override
public Result updateLike(LikeDto likeDto) {
System.out.println(likeDto.toString());
return Result.success();
}
/**
* 实现了InitializingBean接口,通过 type - serviceImpl注入到工厂Map容器中
*/
@Override
public void afterPropertiesSet() throws Exception {
LikeServerFactory.register(LikeFactoryEnum.COMMENT_LIKE.getType(), this);
}
}
5、创建Factory工厂类
@Service
@Slf4j
public 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方法
这种模式下,维护时,我们只需要添加相应的策略服务子类、以及维护一个策略服务类型枚举即可。