首页 > 编程语言 >Java设计模式-策略模式

Java设计模式-策略模式

时间:2023-07-29 11:01:19浏览次数:40  
标签:Java 策略 模式 class charge ChargeStrategy ChargeType 设计模式 public

简介

Java设计模式-策略模式_复杂度

  • 策略模式是指有一定行动内容的相对稳定的策略名称,策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法

经验总结

  • 抽象策略角色: 策略类,通常由一个接口或者抽象类实现
  • 具体策略角色:包装了相关的算法和行为
  • 环境角色:持有一个策略类的引用,最终给客户端调用

应用场景

  1. 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为
  2. 一个类定义了多种行为,并且这些行为在类的操作中以多个条件语句的形式出现

实际应用

  1. 抽象策略类
/**
 * @description 描述
 */
public interface ChargeStrategy {

    /**
     * 计算收费
     *
     * @param cost
     * @return
     */
    double charge(long cost);
}
  1. 具体策略类-内部收费类
/**
 * @description 描述
 */
@TaxTypeAnnotation(taxType = ChargeType.INTERNAL)
class InternalStrategy implements ChargeStrategy {
    @Override
    public double charge(long cost) {
        final double taxRate = 0.2;
        return cost * taxRate;
    }
}
  1. 具体策略类-外部收费类
/**
 * @description 描述
 */
@TaxTypeAnnotation(taxType = ChargeType.EXTERNAL)
class ExternalTaxStrategy implements ChargeStrategy {
    @Override
    public double charge(long cost) {

        return cost;
    }
}
  1. 收费类型枚举


通过if-else获取策略类

/**
 * @description 描述
 */
@Component
public class ChargeStrategyFactory {
    public static ChargeStrategy getChargeStrategy(ChargeType taxType) throws Exception {
        
        if (taxType == ChargeType.INTERNAL) {
            return new InternalStrategy();
        } else if (taxType == ChargeType.EXTERNAL) {
            return new ExternalTaxStrategy();
        } else {
            throw new Exception("未配置相应策略");
        }
    }
}
@Test
public void test1(){
    try {
        ChargeStrategy chargeStrategy = ChargeStrategyFactory.getChargeStrategy(ChargeType.INTERNAL);
        double charge = chargeStrategy.charge(100);
        System.out.println("内部价格:"+charge);

        chargeStrategy = ChargeStrategyFactory.getChargeStrategy(ChargeType.EXTERNAL);
        charge = chargeStrategy.charge(100);
        System.out.println("外部价格:"+charge);

    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 通过传入不同的收费类型,由策略工厂进行判断,赋予相应的处理策略
  • 可以看到,如果通过if语句来获取不同的税策略,当增加新的税策略时就不得不修改已有代码,当方法很多时,就不那么好看,同时也增加了复杂度

通过Map获取策略类

/**
 * @description 描述
 */
public class MapChargeStrategyFactory {
    
    /**
     *存储策略
     */
    static Map<ChargeType, ChargeStrategy> chargeStrategyMap = new HashMap<>();

    // 注册默认策略
    static {
        registerChargeStrategy(ChargeType.INTERNAL, new InternalStrategy());
        registerChargeStrategy(ChargeType.EXTERNAL, new ExternalTaxStrategy());
    }

    /**
     * 提供注册策略接口,外部只需要调用此接口接口新增策略
     */
    public static void registerChargeStrategy(ChargeType taxType, ChargeStrategy taxStrategy) {
        chargeStrategyMap.put(taxType, taxStrategy);
    }

    /**
     * 通过map获取策略,当增加新的策略时无需修改代码
     */

    public static ChargeStrategy getChargeStrategy(ChargeType taxType) throws Exception {
        // 当增加新的税类型时,需要修改代码,同时增加圈复杂度
        if (chargeStrategyMap.containsKey(taxType)) {
            return chargeStrategyMap.get(taxType);
        } else {
            throw new Exception("未配置相应策略");
        }
    }
}
@Test
public void test2(){
    try {
        ChargeStrategy chargeStrategy = MapChargeStrategyFactory.getChargeStrategy(ChargeType.INTERNAL);
        double charge = chargeStrategy.charge(100);
        System.out.println("内部价格:"+charge);

        chargeStrategy = MapChargeStrategyFactory.getChargeStrategy(ChargeType.EXTERNAL);
        charge = chargeStrategy.charge(100);
        System.out.println("外部价格:"+charge);

    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 可以看到,通过map进行获取策略结果相同,进化后if语句没有了,减少了复杂度,增加新的策略后只需调用策略注册接口就好,不需要修改获取策略的代码

通过策略自动注册获取策略类

  • 策略类添加自动注册策略的方法

/**
 * @description 描述
 */
public interface ChargeStrategy {

    /**
     * 计算收费
     *
     * @param cost
     * @return
     */
    double charge(long cost);

    /**
     * 自动注册策略方法
     */
    void register();
}
  • 具体策略实现类
/**
 * @description 描述
 */
@TaxTypeAnnotation(taxType = ChargeType.EXTERNAL)
class ExternalTaxStrategy implements ChargeStrategy {
    @Override
    public double charge(long cost) {

        return cost;
    }

    @Override
    public void register() {
        AutoRegisterChargeStrategyFactory.registerChargeStrategy(ChargeType.EXTERNAL, this);
    }
}
/**
 * @description 描述
 */
@TaxTypeAnnotation(taxType = ChargeType.INTERNAL)
class InternalStrategy implements ChargeStrategy {
    @Override
    public double charge(long cost) {
        final double taxRate = 0.2;
        return cost * taxRate;
    }

    @Override
    public void register() {
        AutoRegisterChargeStrategyFactory.registerChargeStrategy(ChargeType.INTERNAL, this);
    }
}
/**
 * @description 描述
 */
public class AutoRegisterChargeStrategyFactory {

    /**
     * 存储策略
     */
    static Map<ChargeType, ChargeStrategy> chargeStrategyMap = new HashMap<>();

    static {
        autoRegisterTaxStrategy();
    }

    /**
     * 通过map获取策略,当增加新的策略时无需修改代码
     */
    public static ChargeStrategy getChargeStrategy(ChargeType taxType) throws Exception {
        // 当增加新的税类型时,需要修改代码,同时增加圈复杂度
        if (chargeStrategyMap.containsKey(taxType)) {
            return chargeStrategyMap.get(taxType);
        } else {
            throw new Exception("未配置相应策略");
        }
    }

    /**
     * 提供税注册策略接口
     */
    public static void registerChargeStrategy(ChargeType chargeType, ChargeStrategy chargeStrategy) {
        chargeStrategyMap.put(chargeType, chargeStrategy);
    }

    /**
     * 自动注册策略
     */

    private static void autoRegisterTaxStrategy() {
        try {
            // 通过反射找到所有的策略子类进行注册
            Reflections reflections = new Reflections(new ConfigurationBuilder()
                    .setUrls(ClasspathHelper.forPackage(ChargeStrategy.class.getPackage().getName()))
                    .setScanners(new SubTypesScanner()));
            Set<Class<? extends ChargeStrategy>> taxStrategyClassSet = reflections.getSubTypesOf(ChargeStrategy.class);

            if (taxStrategyClassSet != null) {
                for (Class<?> clazz : taxStrategyClassSet) {
                    ChargeStrategy chargeStrategy = (ChargeStrategy) clazz.newInstance();
                    // 调用策略的自注册方法
                    chargeStrategy.register();
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            // 自行定义异常处理
            e.printStackTrace();
        }
    }
}
  • 可以看到,通过策略自动注册进行获取策略结果相同,当添加新的税策略时,就完全不需要修改已有的策略工厂代码,基本完美做到开闭原则,唯一需要修改的是类型定义

通过注解减少耦合

  • 新增加自定义注解类
/**
 * @description 描述
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface ChargeTypeAnnotation {
    ChargeType taxType();
}
/**
 * @description 描述
 */
@ChargeTypeAnnotation(taxType = ChargeType.INTERNAL)
class InternalStrategy implements ChargeStrategy {
    @Override
    public double charge(long cost) {
        final double taxRate = 0.2;
        return cost * taxRate;
    }
}
/**
 * @description 描述
 */
public class AnnotationChargeStrategyFactory {

    /**
     * 存储策略
     */
    static Map<ChargeType, ChargeStrategy> chargeStrategyMap = new HashMap<>();

    static {
        registerChargeStrategy();
    }

    /**
     *     通过map获取策略,当增加新的策略时无需修改代码
      */
    public static ChargeStrategy getChargeStrategy(ChargeType chargeType) throws Exception {
        // 当增加新的类型时,需要修改代码
        if (chargeStrategyMap.containsKey(chargeType)) {
            return chargeStrategyMap.get(chargeType);
        } else {
            throw new Exception("未配置相应策略");
        }
    }

    /**
     * 自动注册策略
     */

    private static void registerChargeStrategy() {
        // 通过反射找到所有的策略子类进行注册
        Reflections reflections = new Reflections(new ConfigurationBuilder()
                .setUrls(ClasspathHelper.forPackage(ChargeStrategy.class.getPackage().getName()))
                .setScanners(new SubTypesScanner()));
        Set<Class<? extends ChargeStrategy>> taxStrategyClassSet = reflections.getSubTypesOf(ChargeStrategy.class);

        if (taxStrategyClassSet != null) {
            for (Class<?> clazz : taxStrategyClassSet) {
                // 找到类型注解,自动完成策略注册
                if (clazz.isAnnotationPresent(ChargeTypeAnnotation.class)) {
                    ChargeTypeAnnotation taxTypeAnnotation = clazz.getAnnotation(ChargeTypeAnnotation.class);
                    ChargeType chargeType = taxTypeAnnotation.taxType();
                    try {
                        chargeStrategyMap.put(chargeType, (ChargeStrategy) clazz.newInstance());
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.getStackTrace();
                    }
                }
            }
        }
    }
}


通过Spring注解实现自动注入

@Component
public class PaymentContext {

    /**
     * 将所有实现了 {@link Payment} 接口的实现都放进来
     * 具体怎么获取接口的所有实现,这里就不展开细讲了
     * 如果使用了 Spring 的话,直接使用 {@link Autowired} 注解即可将所有的实现注入进来
     */


    private Map<PaymentWay, Payment> paymentProvider = new HashMap<>();

    /**
     * 这里根据支付方式枚举为 key,以具体支付实现为 value 将所有的支付实现放到 paymentProvider 中
     */
    public PaymentContext(List<Payment> payments) {
        payments.stream().forEach(payment -> {
            paymentProvider.put(payment.getPaymentWay(), payment);
        });
    }

    public void payment(PaymentWay paymentWay) {
        paymentProvider.get(paymentWay).payment();
    }
}
public abstract class Payment {
    abstract void payment();

    abstract PaymentWay getPaymentWay();
}
@Getter
@AllArgsConstructor
public enum PaymentWay {

    ALI_PAY("支付宝支付"),

    WECHAT_PAY("微信支付"),

    UNION_PAY("银联云闪付支付");

    private String desc;
}
@Component
public class WechatPayPayment extends Payment{
    @Override
    public void payment() {
        System.out.println("微信支付");
    }

    @Override
    public PaymentWay getPaymentWay() {
        return PaymentWay.WECHAT_PAY;
    }
}
@Component
public class AliPayPayment extends Payment {
    @Override
    public void payment() {
        System.out.println("支付宝支付");
    }

    @Override
    public PaymentWay getPaymentWay() {
        return PaymentWay.ALI_PAY;
    }
}

标签:Java,策略,模式,class,charge,ChargeStrategy,ChargeType,设计模式,public
From: https://blog.51cto.com/u_16209090/6891003

相关文章

  • javascript数据类型详解
    文章和代码已经归档至【Github仓库:https://github.com/timerring/front-end-tutorial】或者公众号【AIShareLab】回复javascript也可获取。数据类型JavaScript是一种弱类型或者说动态语言。不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。varage=10;//数字型v......
  • 设计模式-备忘录模式在Java中使用示例-象棋悔棋
    场景备忘录模式备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式。备忘录模式结构图 在备忘录模式结构......
  • 设计模式-中介者模式在Java中使用示例-客户信息管理
    场景欲开发客户信息管理窗口界面,界面组件之间存在较为复杂的交互关系:如果删除一个客户,要在客户列表(List)中删掉对应的项,客户选择组合框(ComboBox)中客户名称也将减少一个;如果增加一个客户信息,客户列表中需增加一个客户,且组合框中也将增加一项。中介者模式概述如果在一个系统......
  • odoo _register_hook和_patch_methods组合使用,实现日志功能,效果和java的切面类似
    _register_hook方法是在odoo启动,加载模块时调用,可以在调用期间对某个的模型进行功能增强,比如增加日志下面是一个简单的示例:classLog(models.Model):_name="cn.com.brandmax.log"_description="日志"def_make_read(self):defread(self,fields=N......
  • Java面试题 P13:MySql中,如何定位慢查询
    如何定位慢查询?1、首先介绍一下当时产生问题的场景,具体什么情况慢2、在mysql中开启慢查询日志,设定查询时间超过2秒的都记录到日志中,我们逐步筛查出现慢sql的原因慢查询可能产生的原因:(1)聚合查询(2)多表查询(3)表数据量过大查询(4)深度分页查询 mysql开启慢查询日志配置:(1)打开My......
  • Java面试题 P12:HashMap和HashTable的区别?底层是怎么实现的?
    区别:1、HashMap:是线程不安全的,HashTable:每个方法都加了个线程锁(synchronized修饰),是线程安全的2、HashMap允许key和value为null,而HashTable不允许 底层实现:数据+链表实现  代码示例: 1publicstaticvoidmain(String[]args)2{3//HashMap......
  • 单例模式小记
    1.概念单例模式是一种设计模式。保证一个类只有一个实例,提供一个全局访问点。2.实例构造函数私有化,防止外部创建对象。提供静态成员函数getInstance,获取单例指针。使用静态指针保存单例实例。classSingleton{public:staticSingleton*getInstance(){......
  • 设计模式-桥接模式
    桥接模式(Bridge)模式定义+将抽象部分和实现接口分离,使它们可以独立变化。是一种结构性模式。UML图时序图角色定义抽象类(Abstraction)用于定义抽象类的接口,其中定义了一个Implementation实现类接口的对象,并可以维护该对象,它与Implementation具有关联关系扩充抽象......
  • JavaScript入门基础
    文章和代码已经归档至【Github仓库:<https://github.com/timerring/front-end-tutorial>】或者公众号【AIShareLab】回复javascript也可获取。JavaScript简介布兰登·艾奇(BrendanEich,1961年~),10天完成JavaScript设计。最初命名为LiveScript,后来在与Sun合作之后将其改名为......
  • Java Web|
    1.Spring1.1SpringMVC参数的封装1.传统的URLlocalhost:8080?id=1&name=tom2.基于RESTful风格的URLlocalhost:8080/1/tom前后端分离的开发一般是基于RESTfull,具体规则是4中请求分别表示不同的业务GET查询POST添加PUT修改DELETE删除每个语言使用的时候都一样,是一种规......