大型Java进阶专题(七) 设计模式之委派模式与策略模式
前言
今天开始我们专题的第七课了。本章节将介绍:你写的代码中是否觉得很臃肿,程序中有大量的if...else,想优化代码,精简程序逻辑,提升代码的可读性,这章节将介绍如何通过委派模式、策略模式让你代码更优雅,消除程序大量冗余的代码。本章节参考资料书籍《Spring 5核心原理》中的第一篇 Spring 内功心法(Spring中常用的设计模式)(没有电子档,都是我取其精华并结合自己的理解,一个字一个字手敲出来的)。
委派模式
委派模式的定义及应用场景
委派模式不属于GOF23种设计模式中。委派模式(Delegate Pattern)的基本作用就是负责任务的调用和分配任务,跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。委派模式在Spring中应用非常多,大家常用的DispatcherServlet其实就是用到了委派模式。现实生活中也常有委派的场景发生,例如:老板(Boss)给项目经理(Leader)下达任务,项目经理会根据实际情况给每个员工派发工作任务,待员工把工作任务完成之后,再由项目经理汇报工作进度和结果给老板。我们用代码来模拟下这个业务场景,先来看一下类图:

创建员工接口
package com.study.demo2;
/**
* @ClassName IEmployee
* @Deacription 员工接口
* @Author wang.zhong.yuan
* @Date 2020/7/9 16:36
* @Version 1.0
**/
public interface IEmployee {
/**
* 需要做的工作
* @param command
*/
void doingSomeThing(String command);
}
员工A实现类
package com.study.demo2;
/**
* @ClassName EmployeeA
* @Deacription 员工A
* @Author wang.zhong.yuan
* @Date 2020/7/9 16:38
* @Version 1.0
**/
public class EmployeeA implements IEmployee {
public void doingSomeThing(String command) {
System.out.println("我是员工A,需要做:"+command);
}
}
员工B实现类
package com.study.demo2;
/**
* @ClassName EmployeeB
* @Deacription 员工B
* @Author wang.zhong.yuan
* @Date 2020/7/9 16:48
* @Version 1.0
**/
public class EmployeeB implements IEmployee {
public void doingSomeThing(String command) {
System.out.println("我是员工B,我要做:"+command);
}
}
领导类
package com.study.demo2;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName Leader
* @Deacription 领导类
* @Author wang.zhong.yuan
* @Date 2020/7/9 16:51
* @Version 1.0
**/
public class Leader implements IEmployee {
private Map<String,IEmployee> underling = new HashMap<String, IEmployee>();
public Leader() {
underling.put("注册功能",new EmployeeA());
underling.put("登陆功能",new EmployeeB());
}
/**
* 自己不做事,委派给对应的员工去做
* @param command
*/
public void doingSomeThing(String command) {
underling.get(command).doingSomeThing(command);
}
}
创建BOSS类,安排工作给Leader
package com.study.demo2;
/**
* @ClassName Boss
* @Deacription TODO
* @Author 19054253
* @Date 2020/7/9 17:03
* @Version 1.0
**/
public class Boss {
public void command(String command, Leader leader){
leader.doingSomeThing(command);
}
//测试功能
public static void main(String[] args) {
//客户请求(Boss)、委派者(Leader)、被被委派者(Target)
//委派者要持有被委派者的引用
//代理模式注重的是过程, 委派模式注重的是结果
//策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
//委派的核心:就是分发、调度、派遣
//委派模式:就是静态代理和策略模式一种特殊的组合
Boss boss = new Boss();
Leader leader = new Leader();
boss.command("登陆功能",leader);
}
}
输出结果

通过上面的代码,生动地还原了项目经理分配工作的业务场景,也是委派模式的生动体现。
策略模式
策略模式的定义与应用
策略模式(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。一个系统需要动态地在几种算法中选择一种,都可以用策略模式实现。
代码实现
一个常见的应用场景就是大家在下单支付时会提示选择支付方式,如果用户未选,系统也会默认好推荐的支付方式进行结算。来看一下类图,下面我们用策略模式来模拟此业务场景:

创建支付状态类:
package com.study.demo3;
/**
* @ClassName PayState
* @Deacription 支付状态
* @Author wang
* @Date 2020/7/9 17:48
* @Version 1.0
**/
public class PayState {
private int code;
private Object data;
private String message;
public PayState(int code, Object data, String message) {
this.code = code;
this.data = data;
this.message = message;
}
@Override
public String toString() {
return "PayState{" +
"code=" + code +
", data=" + data +
", message='" + message + '\'' +
'}';
}
}
创建支付接口
package com.study.demo3;
/**
* @ClassName Payment
* @Deacription 支付渠道
* @Author wang
* @Date 2020/7/9 19:12
* @Version 1.0
**/
public interface IPayment {
/**
* 获取支付类型
* @return
*/
String getName();
/**
* 查询余额
* @param uid
* @return
*/
double queryBalance(String uid);
/**
* 支付
* @param uid
* @param amount
* @return
*/
PayState pay(String uid,double amount);
}
创建支付抽象类,完成一些通用的代码:
package com.study.demo3;
/**
* @ClassName AbstractPayment
* @Deacription 支付抽象类
* @Author wang
* @Date 2020/7/9 19:16
* @Version 1.0
**/
public abstract class AbstractPayment implements IPayment{
public PayState pay(String uid, double amount) {
if (queryBalance(uid) < amount){
return new PayState(-1,"支付失败","余额不足");
}
return new PayState(200,"支付成功","共计支付:"+amount);
}
}
创建阿里支付渠道
package com.study.demo3;
/**
* @ClassName AliPay
* @Deacription 支付宝支付
* @Author wang
* @Date 2020/7/9 19:20
* @Version 1.0
**/
public class AliPay extends AbstractPayment {
public String getName() {
return "支付宝支付";
}
public double queryBalance(String uid) {
return 500;
}
}
创建京东支付渠道
package com.study.demo3;
/**
* @ClassName JDPay
* @Deacription 京东支付
* @Author wang
* @Date 2020/7/9 19:22
* @Version 1.0
**/
public class JDPay extends AbstractPayment {
public String getName() {
return "京东支付";
}
public double queryBalance(String uid) {
return 900;
}
}
创建微信支付渠道
package com.study.demo3;
/**
* @ClassName WXPay
* @Deacription 微信支付
* @Author wang
* @Date 2020/7/9 19:23
* @Version 1.0
**/
public class WXPay extends AbstractPayment {
public String getName() {
return "微信支付";
}
public double queryBalance(String uid) {
return 256;
}
}
package com.study.demo3;
/**
* @ClassName Order
* @Deacription 订单类
* @Author wang
* @Date 2020/7/9 19:35
* @Version 1.0
**/
public class Order {
private String uid;
private String orderId;
private double amount;
public Order(String uid,String orderId,double amount){
this.uid = uid;
this.orderId = orderId;
this.amount = amount;
}
//完美地解决了 switch 的过程,不需要在代码逻辑中写 switch 了
//更不需要写 if else if
public PayState pay(){
return pay(PayStrategy.DEFAULT_PAY);
}
public PayState pay(String payKey){
IPayment payment = PayStrategy.get(payKey);
System.out.println("欢迎使用" + payment.getName());
System.out.println("本次交易金额为:" + amount + ",开始扣款...");
return payment.pay(uid,amount);
}
//测试代码
public static void main(String[] args) {
Order order = new Order("123", "AB123", 400);
//这个值是在支付的时候才决定用哪个值 用户自己决定
order.pay("AliPay");
}
}
输出结果:

希望通过大家耳熟能详的业务场景来举例,让小伙伴们更深刻地理解策略模式。
小结
策略模式的优缺点
优点:
1、策略模式符合开闭原则。
2、避免使用多重条件转移语句,如if...else...语句、switch语句
3、使用策略模式可以提高算法的保密性和安全性。
缺点:
1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
2、代码中会产生非常多策略类,增加维护难度。
大型Java进阶专题(七) 设计模式之委派模式与策略模式的更多相关文章
- 大型Java进阶专题(八)设计模式之适配器模式、装饰者模式和观察者模式
前言 今天开始我们专题的第八课了.本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式. ...
- 大型Java进阶专题(九) 设计模式之总结
前言 关于设计模式的文章就到这里了,学习这门多设计模式,你是不是有这样的疑惑,发现很多设计模式很类似,经常会混淆某些设计模式.这章节我们将对设计模式做一个总结,看看各类设计模式有什么区别.需要注意 ...
- 大型Java进阶专题(四) 设计模式之工厂模式
前言 今天开始我们专题的第三课了,开始对设计模式进行讲解,本章节介绍:了解设计模式的由来,介绍设计模式能帮我们解决那些问题以及剖析工厂模式的历史由来及应用场景.本章节参考资料书籍<Sprin ...
- 大型Java进阶专题(五) 设计模式之单例模式与原型模式
前言 今天开始我们专题的第四课了,最近公司项目忙,没时间写,今天抽空继续.上篇文章对工厂模式进行了详细的讲解,想必大家对设计模式合理运用的好处深有感触.本章节将介绍:单例模式与原型模式.本章节参考 ...
- 大型Java进阶专题(一) 前言
前言 各位读者好,本系列为Java进阶专题,为那些有一定工作经验,做了多年业务的码农,希望突破技术瓶颈,但没有形成系统的Java只是体系,缺乏清晰的提升方法和学习路径的人,比如作者本人.该课题的是 ...
- 大型Java进阶专题(六)设计模式之代理模式
代理模式 前言 又开始我的专题了,又停滞了一段时间了,加油继续吧.都知道 SpringAOP 是用代理模式实现,到底是怎么实现的?我们来一探究竟,并且自己仿真手写还原部分细节. 代理模式的应用 在生活 ...
- 大型Java进阶专题(二) 软件架构设计原则(上)
前言 今天开始我们专题的第一课了,也是我开始进阶学习的第一天,我们先从经典设计思想开始,看看大牛市如何写代码的,提升技术审美.提高核心竞争力.本章节参考资料书籍<Spring 5核心原理&g ...
- 大型Java进阶专题(十一) 深入理解JVM (下)
前言 前面我们了解了JVM相关的理论知识,这章节主要从实战方面,去解读JVM. 类加载机制 Java源代码经过编译器编译成字节码之后,最终都需要加载到虚拟机之后才能运行.虚拟机把描述类的数据从 ...
- 大型Java进阶专题(三) 软件架构设计原则(下)
前言 今天开始我们专题的第二课了,本章节继续分享软件架构设计原则的下篇,将介绍:接口隔离原则.迪米特原则.里氏替换原则和合成复用原则.本章节参考资料书籍<Spring 5核心原理>中的 ...
随机推荐
- <VCC笔记> 溢出与unchecked
在程序运算或者数据转换的时候,由于各种数据类型有各自的范围,运算的时候,其结果如果超出这个范围,就被称之为溢出.熟悉C#的同志们应该了解用来解决溢出(Overflow)问题的checked,unche ...
- 全网最完整的Redis入门指导
前言 本文提供全网最完整的Redis入门指导教程,下面我们从下载Redis安装包开始,一步一步的学习使用. 下载Redis 官网提供的Redis安装包是服务于Linux的,而我们需要在Window下使 ...
- TensorFlow从0到1之TensorFlow实现简单线性回归(15)
本节将针对波士顿房价数据集的房间数量(RM)采用简单线性回归,目标是预测在最后一列(MEDV)给出的房价. 波士顿房价数据集可从http://lib.stat.cmu.edu/datasets/bos ...
- .NETCore微服务探寻(一) - 网关
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- maven配置错误之Unable to import maven project: See logs for details
很多朋友在初次使用maven时,都会出现这个问题. 一加载maven项目,即会报出Unable to import maven project这样的错误,哪怕是新的maven项目也不例外. 我查阅了很 ...
- npm 更换镜像,解决cnpm仍然太慢的问题
众所周知,npm官方镜像 https://registry.npmjs.org 极为卡顿,所以考虑换国内镜像. 网上很多人都说用淘宝镜像,但是淘宝镜像由于同步过于频繁导致卡顿. 可以使用华为镜像: n ...
- Zookeeper客户端Apache Curator
本文不对Zookeeper进行介绍,主要介绍Curator怎么操作Zookeeper. Apache Curator是Apache ZooKeeper的Java / JVM客户端库,Apache Zo ...
- Python3使用cookielib模块
同时使用过python2和python3的应该都知道,好多模块在python2中能直接安装,但是到了python3中却无法安装直接使用,同样python3中的好些模块在python2中也是一样 如下: ...
- 多线程集成设计模式--future模式
多线程开发可以更好的发挥多核cpu性能,常用的多线程设计模式有:Future.Master-Worker.Guard Susperionsion 一.什么是Future模型: 该模型是将异步请求和代理 ...
- 使用反应式关系数据库连接规范R2DBC操作MySQL数据库
1. 简介 三月份已经介绍过R2DBC,它是一种异步的.非阻塞的关系式数据库连接规范.尽管一些NoSQL数据库供应商为其数据库提供了反应式数据库客户端,但对于大多数项目而言,迁移到NoSQL并不是一个 ...