需求:
计算:支付100元,支付的实际金额
微信100减20
支付宝100减10快
普通实现
/**
* @param payType 支付方式
*/
public static void getPayMoney(String payType) {
int money = 100;
if (payType.equals("WX")) {
money = money - 20;
} else if (payType.equals("ZFB")) {
money = money - 10;
}
System.out.println(money);
}
public static void main(String[] args) {
getPayMoney("WX");
getPayMoney("ZFB");
}
策略模式,原理就是靠多态代替if
构成:
策略(一般是接口或抽象类)
策略实现(一般是实现类)
策略上下文(一般是类,含有一个类型为策略的私有变量。
且有一个有参的构造方法,参数包含策略,目的是给策略赋值。
还要有一个公有方法,来执行具体策略)
实现思路
1.创建支付宝,微信两个支付方式类(被称为策略的具体实现),类里面都有计算真实付款金额的方法
2.向上抽取,思考两个类的共同点。创金额计算接口,接口中定义计算的方法(接口或者抽象类被称为策略)
3.第一步创建的两个类实现第二步的接口
//微信100减20(策略的具体实现)
class WXPay implements RealMoney {
@Override
public void getPayMoney() {
System.out.println(100 - 20);
}
}
//支付宝100减10快(策略的具体实现)
class ZFBPay implements RealMoney {
@Override
public void getPayMoney() {
System.out.println(100 - 10);
}
}
//定义接口(接口或者抽象类被称为策略)
public interface RealMoney {
/**
* 计算支付100元,支付的实际金额
*/
void getPayMoney();
}
4.前三部对外暴漏接口,所以我们使用接口来调用方法
5.创建策略上下文51.创建类
5.2类的有一个接口类型的成员变量
5.3对外通过构造方法给成员变量赋值
5.4对外提供方法:使用成员变量调用具体方法
//策略上下文
public class Context {
//接口
private RealMoney realMoney;
//使用构造方法给成员变量赋值
public Context(RealMoney realMoney) {
this.realMoney = realMoney;
}
//对外提供的方法
public void execute() {
//执行某个实现类的方法
realMoney.getPayMoney();
}
}
6.如何使用
public class test{
public static void main(String[] args) {
getPayMoney("WX");
}
public static void getPayMoney(String payType) {
if (payType.equals("WX")) {
Context context = new Context(new ZFBPay());
context.execute();
} else if (payType.equals("ZFB")) {
Context context = new Context(new WXPay());
context.execute();
}
}
}
7.封装了半天,就这?if/else还在!再往下看看
8.JDK的策略模式应用
ThreadPoolExecutor(线程池)
来自
ThreadPoolExecutor就是所谓的策略模式的上下文
/**
* Handler called when saturated or shutdown in execute.
*/
private volatile RejectedExecutionHandler handler;
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//....
this.handler = handler;
}
/**
* Invokes the rejected execution handler for the given command.
* Package-protected for use by ScheduledThreadPoolExecutor.
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
其中我们可以找到RejectedExecutionHandler,这个参数代表的是拒绝策略(有四种具体的实现:1、直接抛出异常2、使用调用者的线程来处理3、直接丢掉这个任务4、丢掉最老的任务)
其实这就是策略模式的体现了。
9.也就是说,并不是四种拒绝策略都可能用到项目中,而是Java程序员自己选择一种。
10.如果他不使用策略模式呢?也就是我们传参数1、2、3、4,他根据参数判断使用那个拒绝策略!这样都话ThreadPoolExecutor就出现了if
11.原来策略模式就是多态!Java帮我们判断了!
12.好吧,那如果我还想去掉第六步的if改如何做?map是个好东西,根据key获取v,假如我们接口有1000个实现类,map里面放<类名,类实例>,那我们根据类名就能获取到类的实例,就不用if判断上千次
13:拓展:其实map的get(key)就是list.get(index)的原理,只不过用的index是由key的hashcode取余length得到的,根据get(index)获取到的是一个链条,链条如果是多个元素,就会进行equals查询,链条如果超过8个就是红黑树查找
14:创建一个静态的map,由于是静态map就选ConcurrentHashMap。避免线程安全问题
public class test{
//定义一个map,为了方便就使用map,静态变量一般需要大写且有意义
private static Map<String,? super RealMoney> map = new ConcurrentHashMap<>();
//静态代码块中,将对象new出来并放入map
static {
map.put("WX", new WXPay());
map.put("ZFB",new ZFBPay());
}
//就可以去掉if了
public static void getPayMoney(String payType) {
Context context = new Context((RealMoney) map.get(payType));
context.execute();
}
public static void main(String[] args) {
getPayMoney("WX");
}
}
15.这个思想是否是设计模式?看看简单工厂模式的介绍,原来就是这种模式
简单工厂模式:属于创建型模式又叫做静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。 简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
16.思考:那么之后再次添加一种付款方式就需要重新写一个实现策略接口的类,并且需要在map中添加。
17.如何不需要每次修改map呢?那么我们可以利用注解。自定义注解,注解可以标注在类上,只要被注解标记的类都会被放入map中,这样就可以不用每次修改map
18.如何利用spring框架实现?参考下面的博客地址
来自博客地址
菜鸟教程
任何设计模都是双刃剑
菜鸟教程设计模式讲的不错,都是Java代码的示例