当前位置: 首页 > news >正文

八股文之设计模式

在这里插入图片描述

策略模式

业务场景

现在有这样的一个场景,关联系统送过来一批文件,根据不同类型采取不同解析方式,很多小伙伴肯定会写出一下代码

if(type=="A"){
// 按照A格式解析
}else if("B".equals(type)){
// 按照B格式解析
}else if("C".equals(type)){
// 按照C格式解析
}
。。。
后面还有多种格式

这个代码会出现什么问题?

如果分支变多,这里代码变得臃肿,难以维护,可读性低
如果需要接入新的解析类型,只能在原来代码上修改
专业一点就是以上代码违背面向对象编程开闭原则和单一原则

  • 开闭原则:对扩展开放,对修改关闭,增加或者删除某个逻辑,需要修改原来代码
  • 单一原则:规定一个类只有一个发生变化原因,修改任何类型的分支逻辑代码,都需要改动当前类代码
    这时候我们的利器来了 “策略模式”

定义和理解

定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。

是不是有点抽象,举个通俗易懂例子
孙权看刘备有雄起之意,杀是不能杀了,那会惹天下人唾弃,就想个招儿收拾他一下,那有什么办法呢?孙权有个妹妹——孙尚香,准备招刘备做女婿,然后孙权想办法把刘备软禁起来,孙权的想法还是很单纯的嘛,就是不让你刘备回西川,然后我东吴想干啥就干啥,夺荆州,吞西川也不是不可能的。东吴的想法是好的,无奈中间多了智谋无敌的诸葛亮,他早就预测了东吴有此招数,于是在刘备去东吴招亲之前,特授以伴郎赵云三个锦囊,说是按天机拆开解决棘手问题。
这三个妙计分别是:找乔国老帮忙(也就是走后门了),求吴国太放行(诉苦)以及孙夫人断后,对这三个妙计不熟悉的读者可以去温习一下《三国演义》,这里就不多说了。想想看,这三个计谋有什么相似之处,他们都是告诉赵云要怎么执行,也就是说这三个计谋都有一个方法是执行,具体执行什么内容,每个计谋当然不同了,分析到这里,我们是不是就有这样一个设计思路:三个妙计应该实现的是同一个接口?

策略模式针对一组算法,将每一个算法封装到共同的接口独立的类中,从而使得他们可以相互转换。

应用场景

● 多个类只有在算法或行为上稍有不同的场景。

● 算法需要自由切换的场景。

● 需要屏蔽算法规则的场景。

UML

在这里插入图片描述

策略模式使用

  • 一个接口或者抽象类,里面包含两个方法,一个方法匹配类型,一个是可以替换的逻辑实现方法
  • 不同策略差异化实现(不同实现类)
  • 使用策略模式

妙计接口

public interface IStrategy {
     //每个锦囊妙计都是一个可执行的算法
     public void operate();
}

第一个妙计:乔国老开后门

@Component
public class BackDoor implements IStrategy {
	 @Override
     public void operate() {
             System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
     }
}

第二个妙计:是找吴国太哭诉,企图给自己开绿灯

@Component
public class GivenGreenLight implements IStrategy {
	 @Override
     public void operate() {
             System.out.println("求吴国太开绿灯,放行!");
     }
}

第三个妙计是在逃跑的时候,让新娘子孙夫人断后,谁来砍谁,这是非常好的主意

@Component
public class BlockEnemy implements IStrategy {
     @Override
     public void operate() {
             System.out.println("孙夫人断后,挡住追兵");
     }
}

在这个场景中,三个妙计都有了,那还缺少两个配角:第一,妙计肯定要放到一个地方吧,这么重要的东西要保管呀,也就是承装妙计的锦囊,所以俗称锦囊妙计嘛;第二,这些妙计都要有一个执行人吧,是谁?当然是赵云了,妙计是小亮给的,执行者是赵云。赵云就是一个干活的人,从锦囊中取出妙计,执行,然后获胜。过程非常清晰,我们把完整的过程设计出来

锦囊

public class Context {
     //构造函数,你要使用哪个妙计
     private IStrategy straegy;
     public Context(IStrategy strategy){
       this.straegy = strategy;
     }
     //使用计谋了,看我出招了
     public void operate(){
       this.straegy.operate();
     }
}

通过构造函数把策略传递进来,然后用operate()方法来执行相关的策略方法。三个妙计有了,锦囊也有了,然后就是赵云雄赳赳地揣着三个锦囊,拉着已步入老年行列的、还想着娶纯情少女的刘老爷子去入赘了。嗨,还别说,小亮同志的三个妙计还真是不错

public class ZhaoYun {
     //赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计
     public static void main(String[] args) {
             Context context;
             //刚刚到吴国的时候拆第一个
             System.out.println("---刚刚到吴国的时候拆第一个---");
             context = new Context(new BackDoor()); //拿到妙计
             context.operate();  //拆开执行
             System.out.println("\n\n\n\n\n\n\n\n");
             //刘备乐不思蜀了,拆第二个了
             System.out.println("---刘备乐不思蜀了,拆第二个了---");
             context = new Context(new GivenGreenLight());
             context.operate();  //执行了第二个锦囊
             System.out.println("\n\n\n\n\n\n\n\n");
             //孙权的小兵追来了,咋办?拆第三个
             System.out.println("---孙权的小兵追来了,咋办?拆第三个---");
             context = new Context(new BlockEnemy());
             context.operate();  //孙夫人退兵
             System.out.println("\n\n\n\n\n\n\n\n");
     }
}

单例模式

业务场景

定义和理解

实践应用

UML

工厂模式

业务场景

定义和理解

实践应用

UML

责任链模式

业务场景

定义和理解

实践应用

UML

观察者模式

业务场景

登录注册是最常见的业务场景了,就拿注册来说是,我们经常遇到类似情况,用户注册成功之后,给用户发送短信或者发送邮件,有如下代码

void register(User user){
  insertRegister(user);
  sendMsm();
  sendMobileMsg();
}

这部分代码有什么问题呢,如果产品添加新的需求,现在注册成功的用户,再给发送一条短信通知,于是乎我们又要修改register方法代码,是不是违反开闭原则
并且调用发短信的接口失败了,是不是影响用户注册,这时候是不是得加个异步方法给通知才可以
实际上我们可以使用观察者模式优化

定义和理解

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新

举例说明:韩非子大家都应该记得吧,法家的代表人物,主张建立法制社会,实施重罚制度,真是非常有远见呀!看看现在社会在呼吁什么,建立法制化的社会,这在2000多年前就已经提出了。大家可能还不知道,法家还有一个非常重要的代表人物——李斯。李斯是秦国的丞相,最终被残忍车裂的那位,李斯和韩非子都是荀子的学生,李斯是师兄,韩非子是师弟,若干年后,李斯成为最强诸侯国秦国的上尉,致力于统一全国,于是安插了间谍到各个国家的重要人物的身边,以获取必要的信息,韩非子作为韩国的重量级人物,身边自然有不少间谍,韩非子做的事,李斯都了如指掌,那可是相隔千里!怎么做到的呢?间谍呀!我们先通过程序把这个过程展现一下,看看李斯是怎么监控韩非子的

实践应用

完成某件事之后,异步通知场景比如办理业务成功发送短信,邮件
订阅发布

UML

在这里插入图片描述
我们先来解释一下观察者模式的几个角色名称:

● Subject被观察者

定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

● Observer观察者

观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

● ConcreteSubject具体的被观察者

定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

● ConcreteObserver具体的观察者

每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

观察者模式使用

观察者

/**
 * @description 观察者
 */
public interface Observer {
    void doEvent();
}

被观察者

package com.geekmice.onetomany.eventbus;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class Subject {
    private Vector<Observer> observers = new Vector<>();
    private Integer state;

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        notifyAllObservers(state);
    }

    /**
     * 添加观察者
     */
    public void addServer(Observer observer) {
        observers.add(observer);
    }

    /**
     * @description 删除观察者
     */
    public void removeServer(Observer observer) {
        observers.remove(observer);
    }

    /**
     * @param state
     * @description 通知所有观察者
     * */
    private void notifyAllObservers(Integer state) {
        if (state != 1) {
            System.out.println("不是通知的状态");
            return;
        }
        for (Observer obj : observers) {
            obj.doEvent();
        }
    }

}

发送邮件被观察者

package com.geekmice.onetomany.eventbus;

public class EmailObserver implements  Observer{

    @Override
    public void doEvent() {
        System.out.println("发送email");
    }
}

发送短信被观察者

package com.geekmice.onetomany.eventbus;

public class MSMessageObserver implements  Observer {
    @Override
    public void doEvent() {
        System.out.println("发送MSM短信");
    }
}

场景类

package com.geekmice.onetomany.eventbus;

public class Context {
    public static void main(String[] args) {
        Subject observerAble = new Subject();
        observerAble.setState(1);
        Observer observer = new EmailObserver();
        observerAble.addServer(observer);
        observer.doEvent();
        Observer msMessageObserver = new MSMessageObserver();
        observerAble.addServer(observer);
        msMessageObserver.doEvent();
    }
}

eventbus优化

Guava EventBus封装好观察者模式,提供了一套基于注解的事件总线,api可以灵活的使用,美滋滋

被观察者

package com.geekmice.onetomany.eventbus;

import com.google.common.eventbus.EventBus;

public class EventBusCenter {
    private static EventBus eventBus = new EventBus();

    private EventBusCenter() {
    }

    public static EventBus getInstance() {
        return eventBus;
    }

    /**
     * @description 添加观察者
     * @param obj
     */
    public static void register(Object obj) {
        eventBus.register(obj);
    }

    /**
     * @description 删除观察者
     * @param object
     */
    public static void unregister(Object object) {
        eventBus.unregister(object);
    }

    /**
     * @description 把消息推送给观察者
     * @param object
     */
    public static void post(Object object) {
        eventBus.post(object);
    }
}

观察者

package com.geekmice.onetomany.eventbus;

import com.google.common.eventbus.Subscribe;
// 声明观察者
public class EventListener {
    // 加了订阅,这里标记这个方法是事件处理方法
    @Subscribe
    public void handle(NotifyEvent notifyEvent) {
        System.out.println("发送IM消息" + notifyEvent.getImNo());
        System.out.println("发送短信消息" + notifyEvent.getMobileNo());
        System.out.println("发送mail消息" + notifyEvent.getEmailNo());
    }
}

事件通知类

package com.geekmice.onetomany.eventbus;
// 通知事件类
public class NotifyEvent {
    private String mobileNo;
    private String emailNo;
    private String imNo;

    public NotifyEvent(String mobileNo, String emailNo, String imNo) {
        this.mobileNo = mobileNo;
        this.emailNo = emailNo;
        this.imNo = imNo;
    }

    public String getMobileNo() {
        return mobileNo;
    }

    public void setMobileNo(String mobileNo) {
        this.mobileNo = mobileNo;
    }

    public String getEmailNo() {
        return emailNo;
    }

    public void setEmailNo(String emailNo) {
        this.emailNo = emailNo;
    }

    public String getImNo() {
        return imNo;
    }

    public void setImNo(String imNo) {
        this.imNo = imNo;
    }
}

demo测试

package com.geekmice.onetomany.eventbus;

public class Client {
    public static void main(String[] args) {
        EventListener eventListener = new EventListener();
        EventBusCenter.register(eventListener);
        EventBusCenter.post(new NotifyEvent("1660702****", "1233445@163.com", "666"));
    }
}

发送IM消息666
发送短信消息1660702****
发送mail消息1233445@163.com

策略模式

相关文章:

  • 第6章 初识Spring框架
  • 【明年找到好工作】:面试题打卡第二天
  • 企业Java实战面试题
  • 多次握手登录
  • gdb调试 常用命令
  • 华为云上安装mysql-5.7.38-极其详细的安装教程
  • vue父子组件传值:父传子、子传父
  • 使用花生壳做内网穿透
  • 基于SSM的学生宿舍管理系统
  • 第二章第六节 ST图与迭代优化
  • Kotlin(九)类、属性、构造函数
  • Java 八股文能不背吗?Java 面试都只是背答案吗?
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • JS垃圾回收与内存泄漏
  • MySQL数据库笔记
  • 【comparator, comparable】小总结
  • 08.Android之View事件问题
  • Angular 响应式表单 基础例子
  • Just for fun——迅速写完快速排序
  • laravel with 查询列表限制条数
  • markdown编辑器简评
  • React as a UI Runtime(五、列表)
  • Vultr 教程目录
  • 阿里云Kubernetes容器服务上体验Knative
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 仿天猫超市收藏抛物线动画工具库
  • 码农张的Bug人生 - 见面之礼
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 阿里云API、SDK和CLI应用实践方案
  • ​​​​​​​​​​​​​​Γ函数
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • !!Dom4j 学习笔记
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (3)nginx 配置(nginx.conf)
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (Git) gitignore基础使用
  • (八十八)VFL语言初步 - 实现布局
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (分布式缓存)Redis分片集群
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四)模仿学习-完成后台管理页面查询
  • (转)shell调试方法
  • (转)大型网站的系统架构
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .gitignore文件---让git自动忽略指定文件
  • .libPaths()设置包加载目录
  • .naturalWidth 和naturalHeight属性,
  • .Net Core和.Net Standard直观理解
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。