消灭if-else (模板+策略+工厂)

涉及知识点:

  1. 枚举+枚举配置抽象类

  2. 函数式接口

  3. 设计模式

    • 策略模式

    • 模板方法

    • 工厂模式

    • 单例模式

代码实例

  • 策略模式,定义抽象接口,不同的实现类实现不同的策略
  • 模板方法,定义一个模板方法,把公共流程写在模板方法中,然后不同的子类按需实现模板方法流程中的方法
  • 单例和工厂是按需
1
2
3
4
5
6
7
8
9
10
11
12
/** 策略业务接口 */
public interface AwardStrategy {
/**
* 奖励发放接口
*/
Map<String, Boolean> awardStrategy(String userId);

/**
* 获取策略标识,即不同渠道的来源标识
*/
String getSource();
}

定义奖励发放模板流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** 定义奖励发放模板流程 */
public abstract class BaseAwardTemplate {
private static final Logger log = LoggerFactory.getLogger(BaseAwardTemplate.class);

//奖励发放模板方法
public Boolean awardTemplate(String userId) {
this.authentication(userId);
this.risk(userId);
return this.awardRecord(userId);
}

//身份验证
protected void authentication(String userId) {
log.info("{} 执行身份验证!", userId);
}

//风控
protected void risk(String userId) {
log.info("{} 执行风控校验!", userId);
}

//执行奖励发放
protected abstract Boolean awardRecord(String userId);
}

实现不同渠道的奖励业务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Slf4j
@Service
public class ToutiaoAwardStrategyService extends BaseAwardTemplate implements AwardStrategy {
/**
* 奖励发放接口
*/
@Override
public Boolean awardStrategy(String userId) {
return super.awardTemplate(userId);
}

@Override
public String getSource() {
return "toutiao";
}

/**
* 具体的业务奖励发放实现
*/
@Override
protected Boolean awardRecord(String userId) {
log.info("头条渠道用户{}奖励50元红包!", userId);
return Boolean.TRUE;
}
}


@Slf4j
@Service
public class WeChatAwardStrategyService extends BaseAwardTemplate implements AwardStrategy {
/**
* 奖励发放接口
*/
@Override
public Boolean awardStrategy(String userId) {
return super.awardTemplate(userId);
}

@Override
public String getSource() {
return "wx";
}

/***
* 具体的业务奖励发放实现
*/
@Override
protected Boolean awardRecord(String userId) {
log.info("微信渠道用户{}奖励100元红包!", userId);
return Boolean.TRUE;
}
}

定义工厂方法,对外统一暴露业务调用入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Component
public class AwardStrategyFactory implements ApplicationContextAware {
private final static Map<String, AwardStrategy> MAP = new HashMap<>();

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, AwardStrategy> beanTypeMap = applicationContext.getBeansOfType(AwardStrategy.class);
beanTypeMap.values().forEach(strategyObj -> MAP.put(strategyObj.getSource(), strategyObj));
}

/**
* 对外统一暴露的工厂方法
*/
public Boolean getAwardResult(String userId, String source) {
AwardStrategy strategy = MAP.get(source);
if (Objects.isNull(strategy)) {
throw new RuntimeException("渠道异常!");
}
return strategy.awardStrategy(userId);
}

/**
* 静态内部类创建单例工厂对象
*/
private static class CreateFactorySingleton {
private static AwardStrategyFactory factory = new AwardStrategyFactory();
}

public static AwardStrategyFactory getInstance() {
return CreateFactorySingleton.factory;
}
}

业务入口方法:

1
2
3
4
5
6
7
8
9
@RestController
@RequestMapping("/activity")
public class ActivityController {

@PostMapping("/reward3")
public void reward3(String userId, String source) {
AwardStrategyFactory.getInstance().getAwardResult(userId, source);
}
}

模板模式和策略模式的区别

策略模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
interface Strategy {
public int doOperation(int num1, int num2);
}

class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}

class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}

class Context {
private Strategy strategy;

public Context(Strategy strategy){
this.strategy = strategy;
}

public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}

模版模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();

//template method
public final void play(){

//initialize the game
initialize();

//start game
startPlay();

//end game
endPlay();
}
}

class Cricket extends Game {
void endPlay() {
System.out.println("Cricket Game Finished!");
}
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}

class Football extends Game {
void endPlay() {
System.out.println("Football Game Finished!");
}
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}

从上面代码可以看出:

  • 策略模式通过has-a的组合方式去实现,在代码运行的时候根据传入参数来动态的确定策略
  • 模板模式通过is-a的继承方式去实现,每一个子类都代表一种不同的模板实现

所以策略和模板经常跟工厂一同出现:模板的抽象和子类决定实现流程,策略在运行的时候动态决定哪一个子目标,工厂用来生产

引自:https://mp.weixin.qq.com/s/qTmw1pHvzcMJPB6fbBHaZg


消灭if-else (模板+策略+工厂)
http://coder-xieshijie.cn/2023/06/12/CodeAesthetic/设计模式/消灭if-else-模板-策略-工厂/
作者
谢世杰
发布于
2023年6月12日
许可协议