设计模式-策略模式

221. 策略模式是一个非常简单且非常实用的一种设计模式

策略模式的核心是选择,动态切换 ,通过条件拿到相应的策略 () , 本质上是对行为的抽象

2. 示例演示 - 定义不同的玩家客服和选择逻辑

2.1 起一个有意义的接口名字时更能反映出接口名字相应的内容

java 复制代码
package org.example.service;

// 客服的通用接口

public interface CustomerService  {
    String findCustomer();
}

2.2 定义四种不同的客服的实现,然后都交给Spring容器管理

java 复制代码
import org.example.controller.SupportUserType;
import org.springframework.stereotype.Service;

@Service
@SupportUserType(CustomerType.BIG)
public class BigCustomerService implements CustomerService {


    @Override
    public String findCustomer() {
        return "BigCustomerService";
    }

}

import org.example.controller.SupportUserType;
import org.springframework.stereotype.Service;

@Service
@SupportUserType(CustomerType.SUPER)
public class SuperRCustomerService implements CustomerService {

    @Override
    public String findCustomer() {
        return "SuperRCustomerService";
    }
}




import org.springframework.stereotype.Component;

@Service
public class DefaultCustomService implements CustomerService{


    @Override
    public String findCustomer() {
        return "没有找到客服";
    }
}



import org.example.controller.SupportUserType;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

@Service
//@Order(4)
@SupportUserType(CustomerType.NORMAL)
public class NormalCustomerService implements CustomerService {


    @Override
    public String findCustomer() {
        return "NormalCustomerService";
    }
}


import org.springframework.stereotype.Component;

@Component
public class DefaultCustomService implements CustomerService{


    @Override
    public String findCustomer() {
        return "没有找到客服";
    }
}

2.3 定义枚举类 每种不同的客服对应不同的金额,使用函数式接口判断不同的类型。不同的金额对应的类型不同。

java 复制代码
import java.util.function.IntPredicate;

// 定义 客服类型的一个枚举 字符串
public enum CustomerType {

    NORMAL(e-> e>0 && e<1000),

    BIG(e-> e>=1000 && e<2000),

    SMAIL(e-> e>=2000 && e<3000),

    SUPER(e-> e>=3000 && e<4000);

    private final IntPredicate support;

    CustomerType( IntPredicate support ) {
         this.support = support;
    }

    public static CustomerType typeOf( int reChange ) {
        for (CustomerType value : values()) {
            if(value.support.test( reChange )) {
                return value;
            }
        }
        return null;
    }
}

2.4 创建枚举,对每种客服的实现类进行标识。

java 复制代码
import org.example.service.CustomerType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportUserType {
    CustomerType value();
}

2.2 代码有具体实现,亦如下

java 复制代码
import org.example.controller.SupportUserType;
import org.springframework.stereotype.Service;

@Service
@SupportUserType(CustomerType.BIG)
public class BigCustomerService implements CustomerService {


    @Override
    public String findCustomer() {
        return "BigCustomerService";
    }

}

2.5 通过反射的方式都文件进行解析和加载,在analystType方法中加上@Resource注解,在Spring容器初始化阶段 ,将解析到的类型和类型对应的实现放入到一个map中,当用户请求相应的controller接口时,就会将金额解析成为对应的枚举,并通过枚举拿到对应的实例对象,通过对象拿到相应的方法,当然当用户输入的金额是非法无法匹配时则直接会返回一个默认的对象。

java 复制代码
import jakarta.annotation.Resource;
import org.example.service.CustomerService;
import org.example.service.CustomerType;
import org.example.service.DefaultCustomService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/customer")
public class CustomerController {

    private Map<CustomerType,CustomerService> map;

    // 手动注入
    @Resource
    private DefaultCustomService defaultCustomService;

    @GetMapping("/customer/{reChange}")
    public String controller(@PathVariable(value = "reChange") Integer reChange) {
        CustomerType customerType = CustomerType.typeOf(reChange);
        CustomerService customerService = map.getOrDefault(customerType , defaultCustomService);
        return customerService.findCustomer();
    }

   // Spring 的 Bean 容器注入时就会执行该方法
    @Resource
    public void analystType(List<CustomerService>  customerServices ) {
        map = customerServices.stream()
                .filter(customerService -> customerService.getClass().isAnnotationPresent(SupportUserType.class))
                .collect(Collectors.toMap(this::findCustomerType, Function.identity()));
       // 策略和处理器的数量的一致性
        if (this.map.size() != CustomerType.values().length ) {
            throw new IllegalStateException("Customer type count mismatch 由用户类型没有对应的策略");
        }
    }


    private CustomerType findCustomerType(CustomerService customerService) {
        SupportUserType annotation = customerService.getClass().getAnnotation(SupportUserType.class);
        return annotation.value();

    }


}
相关推荐
张小姐的猫6 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
杨充9 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充9 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充9 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充9 小时前
2.面向对象的特性
设计模式
杨充9 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充9 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充9 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯13 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法