这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
我们通过两篇文章《挑战工厂模式》、《挑战策略模式》分别介绍了两种模式的模型、适用场景、优缺点。在我们实际开发业务中,往往单独使用一种模式是不能解决实际问题,有时我们需要根据实际需求组合模式达到目的,这篇文章我们来讲讲基于两种模式混合实现一个返奖逻辑。
一、返奖流程介绍
返奖流程的业务逻辑视图如下:
- 首先我们要根据访问的用户Id确定用户的特征信息,比如新用户、老用户等等。
- 接着要判断用户的特征,选择具体的返奖策略,并执行策略。
- 返奖策略执行完成后,对所有的用户都有统一的处理逻辑,比如持久化,通知其它服务等等。
二、业务流程分析
通过流程分析,可以很清楚的看到,对于所有特征的用户,经历的返奖流程是保持一致的,唯一有区别或者说是有变化的是返奖规则。对于这样的业务流程,我们可参考开闭原则。
Software entities (classes, modules, functions) should be open for extension but closed for modification。
官方定义开闭原则:软件实体(包括类、模块、功能等)应该对扩展开放,但是对修改关闭。对扩展开放,表示模块通过扩展的方式去应对需求的变化;对修改关闭,表示当需求变化时,应该尽可能关闭对模块源代码的修改。
所以套用开闭原则,我们应该对于返奖流程保持封闭,对于极有可能扩展的返奖规则保持开放。我们将返奖规则抽象为返奖策略,即针对不同用户类型的不同返奖方案,我们视为不同的返奖策略,不同的返奖策略会产生不同的返奖金额结果。
很显然,我们现在抽象了一个返奖策略,当然是要使用策略模式,然后返奖策略的产生需要统一产生,所以我们需要一个工厂,即使用工厂模式。
三、代码实现
首先我们要定义一个抽象的策略,它能完成两件事情,第一步是执行返奖策略并获取金额,第二步是执行获得返奖策略后的操作。
public interface RewardStrategy {
int rewardBy(String userTrait);
void afterReward(String userTrait,int rewardAmount);
}
因为第二个步骤的执行对于所有用户执行逻辑都是一致的,所以准备一个抽象类去实现afterReward
方法。
public abstract class AbstractRewardStrategy implements RewardStrategy{
@Override
public abstract int rewardBy(String userTrait);
@Override
public void afterReward(String userTrait, int rewardAmount) {
//执行奖励策略后统一要处理的事情
System.out.println("do something after reward");
}
}
接着就是具体的返奖策略类,我们默认实现NewUserRewardStrategy
和OldUserRewardStrategy
两个返奖策略。
public class NewUserRewardStrategy extends AbstractRewardStrategy{
@Override
public int rewardBy(String userTrait) {
return 10;
}
}
public class OldUserRewardStrategy extends AbstractRewardStrategy{
@Override
public int rewardBy(String userTrait) {
//老用户还想有奖励?
return 0;
}
}
具体的策略准备好了,但是对于策略模式我们还要准备一个使用的context
。
public class RewardContext {
final RewardStrategy rewardStrategy;
public RewardContext(RewardStrategy rewardStrategy){
this.rewardStrategy = rewardStrategy;
}
public void doStrategy(String userTrait){
final int rewardAmount = rewardStrategy.rewardBy(userTrait);
rewardStrategy.afterReward(userTrait,rewardAmount);
}
}
至此,策略模式的部分完成,接着我们来实现工厂模式的部分。
public abstract class StrategyFactory<T> {
abstract RewardStrategy createStrategy(Class<T> c);
}
public class FactorRewardStrategyFactory extends StrategyFactory {
@SneakyThrows
@Override
RewardStrategy createStrategy(Class clazz) {
return (RewardStrategy)clazz.newInstance();
}
}
然后我们客户端的使用的代码如下。
public class RewardApp {
static final String NEW_USER_TRAIT = "traitOfNewUser";
static final String OLD_USER_TRAIT = "traitOfOldUser";
public static void main(String[] args) {
if(args == null || args.length ==0){
throw new IllegalArgumentException("args error");
}
final String userTrait = args[0];
final FactorRewardStrategyFactory factorRewardStrategyFactory = new FactorRewardStrategyFactory();
RewardStrategy strategy;
if(userTrait.equals(NEW_USER_TRAIT)){
strategy = factorRewardStrategyFactory.createStrategy(NewUserRewardStrategy.class);
}else if(userTrait.equals(OLD_USER_TRAIT)){
strategy = factorRewardStrategyFactory.createStrategy(OldUserRewardStrategy.class);
}else{
throw new IllegalArgumentException("Unknown userTrait");
}
final RewardContext rewardContext = new RewardContext(strategy);
rewardContext.doStrategy(userTrait);
}
}
至此,返奖流程实现完成,URL
类图如下。
四、总结
策略模式保证了我们可以根据业务需求动态的切换策略,而不必改动我们的代码逻辑。工厂模式帮助我们去使用具体的策略,而不再关心创建对象过程中的逻辑。
通过两种模式的组合,当我们需要丰富策略时,我们只是需要继承实现AbstractRewardStrategy
抽象类,不必动其它的代码逻辑。这样提高了服务的扩展性,在一定程度上做到了高内聚、低耦合。