策略模式(Strategy Pattern):一个类的行为或其算法可以在运行时更改,策略模式属于行为型模式。
策略模式简单Java实现: https://www.runoob.com/design-pattern/strategy-pattern.html
策略模式本质就是利用类型的多态,通过接口不同实现类来实现不同的功能
SpringBoot实现
场景:假设登录系统的用户有多种,例如:终身会员、年度会员、月度会员、普通用户,每种用户购买商品折扣不同
创建用户类型枚举
@Getter
@AllArgsConstructor
public enum UserTypeEnum {
/**
* 终身会员
* 年度会员
* 月度会员
* 普通用户
*/
LIFETIME_MEMBER(2, BigDecimal.valueOf(0.2), "终身会员"),
ANNUAL_MEMBER(3, BigDecimal.valueOf(0.5), "年度会员"),
MONTHLY_MEMBER(4, BigDecimal.valueOf(0.75), "月度会员"),
USER(5, BigDecimal.valueOf(1), "普通用户");
/** 用户类型code */
private final int code;
/** 用户折扣 */
private final BigDecimal discount;
/** 用户类型 */
private final String desc;
}
创建用户Service接口
UserService接口定义了default方法,子类可以选择重写,不重写则使用默认方法
例如默认类型为:普通用户
默认购买方法为:购买金额 =金额 × 折扣
public interface UserService {
/**
* 获取用户类型
* @return 用户类型枚举
*/
default UserTypeEnum getUserType() {
return UserTypeEnum.USER;
}
/**
* 默认扣除金额的方式
* 金额 × 折扣
* @param price 金额
* @return 折后金额
*/
default BigDecimal calcPrice(String price) {
return new BigDecimal(price).multiply(getUserType().getDiscount());
}
}
创建实现类
重写getUserType()方法
LifetimeMemberUserServiceImpl
AnnualMemberUserServiceImpl
MonthlyMemberUserServiceImpl
不重写默认方法
NoramlUserServiceImpl
@Service
public class AnnualMemberUserServiceImpl implements UserService {
@Override
public UserTypeEnum getUserType() {
return UserTypeEnum.ANNUAL_MEMBER;
}
}
创建ShoppingService调用UserService
采用构造器注入,通过SpringBoot自动注入将所有类型为UserService的实现类注入进来并收集成一个key为用户类型,value为UserService的Map,此时通过当前登录用户的userType决定调用哪个具体UserService实现类,达到去除if else的目的
@Service
public class ShoppingServiceImpl implements ShoppingService {
@Resource
private LoginService loginService;
private final Map<UserTypeEnum, UserService> userServiceMap;
public ShoppingServiceImpl(List<UserService> userServices) {
userServiceMap = userServices.stream()
.collect(Collectors.toMap(UserService::getUserType, userService -> userService));
}
@Override
public String calcPrice(String price) {
// 获取当前登录用户
User loginUser = loginService.getLoginUser();
// 主要业务流程
try {
// 计算折扣
UserService userService = userServiceMap.get(loginUser.getUserType());
BigDecimal calcResult = userService.calcPrice(price);
String result = calcResult.toPlainString();
// 假设扣除用户余额
System.out.println("用户扣除余额 = " + result);
} catch (Exception e) {
return "error";
}
return "success";
}
}
创建单元测试类或接口进行测试
@SpringBootTest
class Springboot3ApplicationTests {
@Resource
private ShoppingService shoppingService;
@Test
void contextLoads() {
String result = shoppingService.calcPrice("56");
}
}