Java设计模式之策略模式

Java设计模式之策略模式

一、策略模式简介

策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。

二、策略模式使用场景
2.1. 策略模式组成

这个模式涉及到三个角色:

  • 环境(Context)角色:持有一个Strategy的引用。
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
2.2. 使用场景
  • 去掉硬编码,可以用策略模式进行优化;(例如:不同用户不同的结算方法)
  • 动态切换数据源; (例如:可以动态切换Mysql或者 oracle 数据库)
  • 其他的具体看业务或者架构去实际使用吧。说白了就是对多个if...else的优化。
2.3. 优缺点

优点: 替换继承关系,避免使用多重条件转移语句。

缺点: 客户端必须知道所有策略类,并自行决定使用哪一种策略类。如果算法较多,则会造成很多的策略类。

三、策略模式实现

抽象策略角色:

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName Strategy.java
 * @Description 四则运算策略接口
 * @createTime 2019年11月15日
 */
public interface Strategy {

    /**
     * 操作
     * @param a
     * @param b
     * @return
     */
    Integer operator(Integer a, Integer b);

}

具体四则运算实现:

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName AddStrategy.java
 * @Description 加法操作策略
 */
public class AddStrategy implements Strategy {

    @Override
    public Integer operator(Integer a, Integer b) {
        return a + b;
    }
}

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName DivStrategy.java
 * @Description 除法操作策略
 */
public class DivStrategy implements Strategy {

    @Override
    public Integer operator(Integer a, Integer b) {
        return a / b;
    }
}

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName MulStrategy.java
 * @Description 乘法操作策略
 */
public class MulStrategy implements Strategy {

    @Override
    public Integer operator(Integer a, Integer b) {
        return a * b;
    }
}

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName SubStrategy.java
 * @Description 减法操作策略
 */
public class SubStrategy implements Strategy {

    @Override
    public Integer operator(Integer a, Integer b) {
        return a - b;
    }
}

上下文类 :

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName Context.java
 * @Description 上下文类
 */
public class Context {

    private Strategy strategy;

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

    public Integer getResult(Integer a, Integer b) {
        return strategy.operator(a, b);
    }

}

测试类:

public class Main {

    public static void main(String[] args) {
        Integer a = 10, b = 90;
        Integer res = new Context(new AddStrategy()).getResult(a ,b);
        System.out.println("a (" +  a + ") + b (" + b + ") = " + res);
    }
    
}

四、策略模式与工厂模式的区别
4.1. 相同之处:
  1. 都有一个抽象类或者公共接口,并且在抽象类中需要顶一个抽象方法;
  2. 总体来说,模式结构上差不多。
4.2. 不同之处
  1. 工厂模式主要使用来创建对象(创建型模式,关注对象创建),通过不同的条件创建对象;
  2. 策略模式主要是实现的封装(同一个对象的不同行为,主要关注行为的选择),算法不同,需要增加子类进行实现;
  3. 策略模式需要有一个上下文类,通过组合方式(不是继承)获取子类,并且提供统一的客户端接口。
五、策略模式和工厂模式整合

只需要修改上下文类:

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName Context.java
 * @Description TODO
 */
public class Context {

    private Strategy strategy;

    // 整合和工厂模式创建实现类
    public Context(Class clazz)  {
        try {
            this.strategy = (Strategy) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Integer getResult(Integer a, Integer b) {
        return strategy.operator(a, b);
    }

}

测试类:

public class Main {

    public static void main(String[] args) {
        Integer a = 10, b = 90;
        Integer res = new Context(new AddStrategy()).getResult(a ,b);
        System.out.println("a (" +  a + ") + b (" + b + ") = " + res);
    }
    
}

六、进阶:策略枚举

在设计模式之禅中还有一个策略枚举的方法可以实现。其实很简单,简单介绍下,我们还是对上面的那个四则运算的策略方法进行修改。

/**
 * @author 墨龙吟
 * @version 1.0.0
 * @ClassName StrategyEnum.java
 * @Description 策略枚举
 */
public enum  StrategyEnum {
    /** 加法 */
    ADD("+") {
        @Override
        public Integer operator(Integer a, Integer b) {
            return a + b;
        }
    },
    /** 减法 */
    SUB("-") {
        @Override
        public Integer operator(Integer a, Integer b) {
            return a - b;
        }
    },
    /** 除法 */
    DIV("/") {
        @Override
        public Integer operator(Integer a, Integer b) {
            return a / b;
        }
    },
    /** 乘法 */
    MUL("*") {
        @Override
        public Integer operator(Integer a, Integer b) {
            return a * b;
        }
    }
    ;
    private String key;

    StrategyEnum(String key) {
        this.key = key;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public abstract Integer operator(Integer a, Integer b);

}

测试:

public class Main {
    public static void main(String[] args) {
        System.out.println(StrategyEnum.ADD.operator(2, 5));
        System.out.println(StrategyEnum.SUB.operator(2, 5));
        System.out.println(StrategyEnum.DIV.operator(2, 5));
        System.out.println(StrategyEnum.MUL.operator(2, 5));
    }
}
七、总结

设计模式关键,还是在实际代码中的使用体验,在完成日常开发的过程中,对自己写的代码想想是不是还有优化空间,力求写出完美的代码,一直在学习的路上,一起加油!

最后欢迎关注下公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值