前言

​ 今天开始我们专题的第七课了。本章节将介绍:你写的代码中是否觉得很臃肿,程序中有大量的if...else,想优化代码,精简程序逻辑,提升代码的可读性,这章节将介绍如何通过委派模式、策略模式让你代码更优雅,消除程序大量冗余的代码。本章节参考资料书籍《Spring 5核心原理》中的第一篇 Spring 内功心法(Spring中常用的设计模式)(没有电子档,都是我取其精华并结合自己的理解,一个字一个字手敲出来的)。

委派模式

委派模式的定义及应用场景

​ 委派模式不属于GOF23种设计模式中。委派模式(Delegate Pattern)的基本作用就是负责任务的调用和分配任务,跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。委派模式在Spring中应用非常多,大家常用的DispatcherServlet其实就是用到了委派模式。现实生活中也常有委派的场景发生,例如:老板(Boss)给项目经理(Leader)下达任务,项目经理会根据实际情况给每个员工派发工作任务,待员工把工作任务完成之后,再由项目经理汇报工作进度和结果给老板。我们用代码来模拟下这个业务场景,先来看一下类图:

创建员工接口

  1. package com.study.demo2;
  2. /**
  3. * @ClassName IEmployee
  4. * @Deacription 员工接口
  5. * @Author wang.zhong.yuan
  6. * @Date 2020/7/9 16:36
  7. * @Version 1.0
  8. **/
  9. public interface IEmployee {
  10. /**
  11. * 需要做的工作
  12. * @param command
  13. */
  14. void doingSomeThing(String command);
  15. }

员工A实现类

  1. package com.study.demo2;
  2. /**
  3. * @ClassName EmployeeA
  4. * @Deacription 员工A
  5. * @Author wang.zhong.yuan
  6. * @Date 2020/7/9 16:38
  7. * @Version 1.0
  8. **/
  9. public class EmployeeA implements IEmployee {
  10. public void doingSomeThing(String command) {
  11. System.out.println("我是员工A,需要做:"+command);
  12. }
  13. }

员工B实现类

  1. package com.study.demo2;
  2. /**
  3. * @ClassName EmployeeB
  4. * @Deacription 员工B
  5. * @Author wang.zhong.yuan
  6. * @Date 2020/7/9 16:48
  7. * @Version 1.0
  8. **/
  9. public class EmployeeB implements IEmployee {
  10. public void doingSomeThing(String command) {
  11. System.out.println("我是员工B,我要做:"+command);
  12. }
  13. }

领导类

  1. package com.study.demo2;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. /**
  5. * @ClassName Leader
  6. * @Deacription 领导类
  7. * @Author wang.zhong.yuan
  8. * @Date 2020/7/9 16:51
  9. * @Version 1.0
  10. **/
  11. public class Leader implements IEmployee {
  12. private Map<String,IEmployee> underling = new HashMap<String, IEmployee>();
  13. public Leader() {
  14. underling.put("注册功能",new EmployeeA());
  15. underling.put("登陆功能",new EmployeeB());
  16. }
  17. /**
  18. * 自己不做事,委派给对应的员工去做
  19. * @param command
  20. */
  21. public void doingSomeThing(String command) {
  22. underling.get(command).doingSomeThing(command);
  23. }
  24. }

创建BOSS类,安排工作给Leader

  1. package com.study.demo2;
  2. /**
  3. * @ClassName Boss
  4. * @Deacription TODO
  5. * @Author 19054253
  6. * @Date 2020/7/9 17:03
  7. * @Version 1.0
  8. **/
  9. public class Boss {
  10. public void command(String command, Leader leader){
  11. leader.doingSomeThing(command);
  12. }
  13. //测试功能
  14. public static void main(String[] args) {
  15. //客户请求(Boss)、委派者(Leader)、被被委派者(Target)
  16. //委派者要持有被委派者的引用
  17. //代理模式注重的是过程, 委派模式注重的是结果
  18. //策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
  19. //委派的核心:就是分发、调度、派遣
  20. //委派模式:就是静态代理和策略模式一种特殊的组合
  21. Boss boss = new Boss();
  22. Leader leader = new Leader();
  23. boss.command("登陆功能",leader);
  24. }
  25. }

输出结果

通过上面的代码,生动地还原了项目经理分配工作的业务场景,也是委派模式的生动体现。

策略模式

策略模式的定义与应用

策略模式(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。一个系统需要动态地在几种算法中选择一种,都可以用策略模式实现。

代码实现

一个常见的应用场景就是大家在下单支付时会提示选择支付方式,如果用户未选,系统也会默认好推荐的支付方式进行结算。来看一下类图,下面我们用策略模式来模拟此业务场景:

创建支付状态类:

  1. package com.study.demo3;
  2. /**
  3. * @ClassName PayState
  4. * @Deacription 支付状态
  5. * @Author wang
  6. * @Date 2020/7/9 17:48
  7. * @Version 1.0
  8. **/
  9. public class PayState {
  10. private int code;
  11. private Object data;
  12. private String message;
  13. public PayState(int code, Object data, String message) {
  14. this.code = code;
  15. this.data = data;
  16. this.message = message;
  17. }
  18. @Override
  19. public String toString() {
  20. return "PayState{" +
  21. "code=" + code +
  22. ", data=" + data +
  23. ", message='" + message + '\'' +
  24. '}';
  25. }
  26. }

创建支付接口

  1. package com.study.demo3;
  2. /**
  3. * @ClassName Payment
  4. * @Deacription 支付渠道
  5. * @Author wang
  6. * @Date 2020/7/9 19:12
  7. * @Version 1.0
  8. **/
  9. public interface IPayment {
  10. /**
  11. * 获取支付类型
  12. * @return
  13. */
  14. String getName();
  15. /**
  16. * 查询余额
  17. * @param uid
  18. * @return
  19. */
  20. double queryBalance(String uid);
  21. /**
  22. * 支付
  23. * @param uid
  24. * @param amount
  25. * @return
  26. */
  27. PayState pay(String uid,double amount);
  28. }

创建支付抽象类,完成一些通用的代码:

  1. package com.study.demo3;
  2. /**
  3. * @ClassName AbstractPayment
  4. * @Deacription 支付抽象类
  5. * @Author wang
  6. * @Date 2020/7/9 19:16
  7. * @Version 1.0
  8. **/
  9. public abstract class AbstractPayment implements IPayment{
  10. public PayState pay(String uid, double amount) {
  11. if (queryBalance(uid) < amount){
  12. return new PayState(-1,"支付失败","余额不足");
  13. }
  14. return new PayState(200,"支付成功","共计支付:"+amount);
  15. }
  16. }

创建阿里支付渠道

  1. package com.study.demo3;
  2. /**
  3. * @ClassName AliPay
  4. * @Deacription 支付宝支付
  5. * @Author wang
  6. * @Date 2020/7/9 19:20
  7. * @Version 1.0
  8. **/
  9. public class AliPay extends AbstractPayment {
  10. public String getName() {
  11. return "支付宝支付";
  12. }
  13. public double queryBalance(String uid) {
  14. return 500;
  15. }
  16. }

创建京东支付渠道

  1. package com.study.demo3;
  2. /**
  3. * @ClassName JDPay
  4. * @Deacription 京东支付
  5. * @Author wang
  6. * @Date 2020/7/9 19:22
  7. * @Version 1.0
  8. **/
  9. public class JDPay extends AbstractPayment {
  10. public String getName() {
  11. return "京东支付";
  12. }
  13. public double queryBalance(String uid) {
  14. return 900;
  15. }
  16. }

创建微信支付渠道

  1. package com.study.demo3;
  2. /**
  3. * @ClassName WXPay
  4. * @Deacription 微信支付
  5. * @Author wang
  6. * @Date 2020/7/9 19:23
  7. * @Version 1.0
  8. **/
  9. public class WXPay extends AbstractPayment {
  10. public String getName() {
  11. return "微信支付";
  12. }
  13. public double queryBalance(String uid) {
  14. return 256;
  15. }
  16. }
  1. package com.study.demo3;
  2. /**
  3. * @ClassName Order
  4. * @Deacription 订单类
  5. * @Author wang
  6. * @Date 2020/7/9 19:35
  7. * @Version 1.0
  8. **/
  9. public class Order {
  10. private String uid;
  11. private String orderId;
  12. private double amount;
  13. public Order(String uid,String orderId,double amount){
  14. this.uid = uid;
  15. this.orderId = orderId;
  16. this.amount = amount;
  17. }
  18. //完美地解决了 switch 的过程,不需要在代码逻辑中写 switch 了
  19. //更不需要写 if else if
  20. public PayState pay(){
  21. return pay(PayStrategy.DEFAULT_PAY);
  22. }
  23. public PayState pay(String payKey){
  24. IPayment payment = PayStrategy.get(payKey);
  25. System.out.println("欢迎使用" + payment.getName());
  26. System.out.println("本次交易金额为:" + amount + ",开始扣款...");
  27. return payment.pay(uid,amount);
  28. }
  29. //测试代码
  30. public static void main(String[] args) {
  31. Order order = new Order("123", "AB123", 400);
  32. //这个值是在支付的时候才决定用哪个值 用户自己决定
  33. order.pay("AliPay");
  34. }
  35. }

输出结果:

希望通过大家耳熟能详的业务场景来举例,让小伙伴们更深刻地理解策略模式。

小结

策略模式的优缺点

优点:

1、策略模式符合开闭原则。

2、避免使用多重条件转移语句,如if...else...语句、switch语句

3、使用策略模式可以提高算法的保密性和安全性。

缺点:

1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。

2、代码中会产生非常多策略类,增加维护难度。

大型Java进阶专题(七) 设计模式之委派模式与策略模式的更多相关文章

  1. 大型Java进阶专题(八)设计模式之适配器模式、装饰者模式和观察者模式

    前言 ​ 今天开始我们专题的第八课了.本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式. ...

  2. 大型Java进阶专题(九) 设计模式之总结

    前言 ​ 关于设计模式的文章就到这里了,学习这门多设计模式,你是不是有这样的疑惑,发现很多设计模式很类似,经常会混淆某些设计模式.这章节我们将对设计模式做一个总结,看看各类设计模式有什么区别.需要注意 ...

  3. 大型Java进阶专题(四) 设计模式之工厂模式

    前言 ​ 今天开始我们专题的第三课了,开始对设计模式进行讲解,本章节介绍:了解设计模式的由来,介绍设计模式能帮我们解决那些问题以及剖析工厂模式的历史由来及应用场景.本章节参考资料书籍<Sprin ...

  4. 大型Java进阶专题(五) 设计模式之单例模式与原型模式

    前言 ​ 今天开始我们专题的第四课了,最近公司项目忙,没时间写,今天抽空继续.上篇文章对工厂模式进行了详细的讲解,想必大家对设计模式合理运用的好处深有感触.本章节将介绍:单例模式与原型模式.本章节参考 ...

  5. 大型Java进阶专题(一) 前言

    前言 ​ 各位读者好,本系列为Java进阶专题,为那些有一定工作经验,做了多年业务的码农,希望突破技术瓶颈,但没有形成系统的Java只是体系,缺乏清晰的提升方法和学习路径的人,比如作者本人.该课题的是 ...

  6. 大型Java进阶专题(六)设计模式之代理模式

    代理模式 前言 又开始我的专题了,又停滞了一段时间了,加油继续吧.都知道 SpringAOP 是用代理模式实现,到底是怎么实现的?我们来一探究竟,并且自己仿真手写还原部分细节. 代理模式的应用 在生活 ...

  7. 大型Java进阶专题(二) 软件架构设计原则(上)

    前言 ​ 今天开始我们专题的第一课了,也是我开始进阶学习的第一天,我们先从经典设计思想开始,看看大牛市如何写代码的,提升技术审美.提高核心竞争力.本章节参考资料书籍<Spring 5核心原理&g ...

  8. 大型Java进阶专题(十一) 深入理解JVM (下)

    前言 ​ 前面我们了解了JVM相关的理论知识,这章节主要从实战方面,去解读JVM. 类加载机制 ​ Java源代码经过编译器编译成字节码之后,最终都需要加载到虚拟机之后才能运行.虚拟机把描述类的数据从 ...

  9. 大型Java进阶专题(三) 软件架构设计原则(下)

    前言 ​ 今天开始我们专题的第二课了,本章节继续分享软件架构设计原则的下篇,将介绍:接口隔离原则.迪米特原则.里氏替换原则和合成复用原则.本章节参考资料书籍<Spring 5核心原理>中的 ...

随机推荐

  1. 如何解决flutter中gradle慢的问题

    初学flutter的时候,flutter run运行到有gradle的时候就停住不动了,研究后解决方法如下: 打开项目目录 中的 ...\myapp\android\gradle\wrapper\gr ...

  2. 利用Python将多个PDF文件合并

    from PyPDF2 import PdfFileMerger import os files = os.listdir()#列出目录中的所有文件 merger = PdfFileMerger() ...

  3. ODEINT 求解常微分方程(2)

    import numpy as np from scipy.integrate import odeint import matplotlib.pyplot as plt # function tha ...

  4. 1.Go 开始搞起

    link 1. IDE Go Land 服务器激活 2. 资源 中文网站 翻译组 翻译组wiki 待认领文章 入门指南 中文文档 fork 更新 github 中如何定期使用项目仓库内容更新自己 fo ...

  5. abp-CMS模块-广告

    无论是开发app还是网站,可能都需要一个广告功能,比如我们常见的在首页有个轮播广告,里面会轮播显示多个图片.还有比如一个新闻门户网站 很常见的 banner横幅广告,还有js特效广告等.本篇说说在ab ...

  6. 油猴脚本 之 网教通直播评论记录抓取 v2.0

    先放一个 <油猴脚本 之 网教通直播评论记录抓取>那篇文章的传送门 . 修复内容 将所有表情转为 [符号表情] 字样,而非删除: 修复被禁言用户读取异常,现在被禁言用户表示为 张三 [已禁 ...

  7. qt解决release后数据库连接不上的问题

    问题 : 明明已经设置了 "./xxx" , 为什么release之后数据库还是连不上呢 解决 : 项目中建立一个plugins文件夹 将qt安装目录下的sqldrivers复制到 ...

  8. c++的两个冒号::四个点是什么意思,什么作用呢?

    c++的两个冒号::四个点是什么意思,什么作用呢? 双冒号(::)用法 (1)表示“域操作符”例:声明了一个类A,类A里声明了一个成员函数void f(),但没有在类的声明里给出f的定义,那么在类外定 ...

  9. VScode Doxygen与Todo Tree插件的使用与安装

    VScode Doxygen与Todo Tree插件的使用与安装 引言 程序中代码注释的规范和统一性是作为工程人员必不可少的技能,本文在Visual Studio Code的环境下简单介绍Doxyge ...

  10. 电商安全无小事,如何有效抵御 CSRF 攻击?

    现在,我们绝大多数人都会在网上购物买东西.但是很多人都不清楚的是,很多电商网站会存在安全漏洞.乌云就通报过,国内很多家公司的网站都存在 CSRF 漏洞.如果某个网站存在这种安全漏洞的话,那么我们在购物 ...