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

java八股文面试[设计模式]——行为型模式

目录

策略模式

观察者模式

责任链模式

模板方法模式

状态模式


行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰。

策略模式

策略模式太常用了

下面设计的场景是,我们需要画一个图形,可选的策略就是用红色笔来画,还是绿色笔来画,或者蓝色笔来画。

首先,先定义一个策略接口:

public interface Strategy {
   public void draw(int radius, int x, int y);
}

然后我们定义具体的几个策略:

public class RedPen implements Strategy {@Overridepublic void draw(int radius, int x, int y) {System.out.println("用红色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);}
}
public class GreenPen implements Strategy {@Overridepublic void draw(int radius, int x, int y) {System.out.println("用绿色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);}
}
public class BluePen implements Strategy {@Overridepublic void draw(int radius, int x, int y) {System.out.println("用蓝色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);}
}

使用策略的类:

public class Context {private Strategy strategy;public Context(Strategy strategy){this.strategy = strategy;}public int executeDraw(int radius, int x, int y){return strategy.draw(radius, x, y);}
}

客户端演示:

public static void main(String[] args) {Context context = new Context(new BluePen()); // 使用绿色笔来画context.executeDraw(10, 0, 0);
}

放到一张图上,让大家看得清晰些:

图片

这个时候,大家有没有联想到结构型模式中的桥梁模式,它们其实非常相似,我把桥梁模式的图拿过来大家对比下:

图片

要我说的话,它们非常相似,桥梁模式在左侧加了一层抽象而已。桥梁模式的耦合更低,结构更复杂一些

观察者模式

观察者模式对于我们来说,真是再简单不过了。无外乎两个操作,观察者订阅自己关心的主题和主题有数据变化后通知观察者们。

首先,需要定义主题,每个主题需要持有观察者列表的引用,用于在数据变更的时候通知各个观察者:

public class Subject {private List<Observer> observers = new ArrayList<Observer>();private int state;public int getState() {return state;}public void setState(int state) {this.state = state;// 数据已变更,通知观察者们notifyAllObservers();}// 注册观察者public void attach(Observer observer) {observers.add(observer);}// 通知观察者们public void notifyAllObservers() {for (Observer observer : observers) {observer.update();}}
}

定义观察者接口:

public abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

其实如果只有一个观察者类的话,接口都不用定义了,不过,通常场景下,既然用到了观察者模式,我们就是希望一个事件出来了,会有多个不同的类需要处理相应的信息。比如,订单修改成功事件,我们希望发短信的类得到通知、发邮件的类得到通知、处理物流信息的类得到通知等。

我们来定义具体的几个观察者类:

public class BinaryObserver extends Observer {// 在构造方法中进行订阅主题public BinaryObserver(Subject subject) {this.subject = subject;// 通常在构造方法中将 this 发布出去的操作一定要小心this.subject.attach(this);}// 该方法由主题类在数据变更的时候进行调用@Overridepublic void update() {String result = Integer.toBinaryString(subject.getState());System.out.println("订阅的数据发生变化,新的数据处理为二进制值为:" + result);}
}public class HexaObserver extends Observer {public HexaObserver(Subject subject) {this.subject = subject;this.subject.attach(this);}@Overridepublic void update() {String result = Integer.toHexString(subject.getState()).toUpperCase();System.out.println("订阅的数据发生变化,新的数据处理为十六进制值为:" + result);}
}

客户端使用也非常简单:

public static void main(String[] args) {// 先定义一个主题Subject subject1 = new Subject();// 定义观察者new BinaryObserver(subject1);new HexaObserver(subject1);// 模拟数据变更,这个时候,观察者们的 update 方法将会被调用subject.setState(11);
}

output:

订阅的数据发生变化,新的数据处理为二进制值为:1011
订阅的数据发生变化,新的数据处理为十六进制值为:B

当然,JDK 也提供了相似的支持,具体的大家可以参考 java.util.Observable 和 java.util.Observer 这两个类。

实际生产过程中,观察者模式往往用消息中间件来实现,如果要实现单机观察者模式,笔者建议读者使用 Guava 中的 EventBus,它有同步实现也有异步实现,本文主要介绍设计模式,就不展开说了。

还有,即使是上面的这个代码,也会有很多变种,大家只要记住核心的部分,那就是一定有一个地方存放了所有的观察者,然后在事件发生的时候,遍历观察者,调用它们的回调函数

责任链模式

责任链通常需要先建立一个单向链表,然后调用方只需要调用头部节点就可以了,后面会自动流转下去。比如流程审批就是一个很好的例子,只要终端用户提交申请,根据申请的内容信息,自动建立一条责任链,然后就可以开始流转了。

有这么一个场景,用户参加一个活动可以领取奖品,但是活动需要进行很多的规则校验然后才能放行,比如首先需要校验用户是否是新用户、今日参与人数是否有限额、全场参与人数是否有限额等等。设定的规则都通过后,才能让用户领走奖品。

如果产品给你这个需求的话,我想大部分人一开始肯定想的就是,用一个 List 来存放所有的规则,然后 foreach 执行一下每个规则就好了。不过,读者也先别急,看看责任链模式和我们说的这个有什么不一样?

首先,我们要定义流程上节点的基类:

public abstract class RuleHandler {// 后继节点protected RuleHandler successor;public abstract void apply(Context context);public void setSuccessor(RuleHandler successor) {this.successor = successor;}public RuleHandler getSuccessor() {return successor;}
}

接下来,我们需要定义具体的每个节点了。

校验用户是否是新用户:

public class NewUserRuleHandler extends RuleHandler {public void apply(Context context) {if (context.isNewUser()) {// 如果有后继节点的话,传递下去if (this.getSuccessor() != null) {this.getSuccessor().apply(context);}} else {throw new RuntimeException("该活动仅限新用户参与");}}
}

验用户所在地区是否可以参与:

public class LocationRuleHandler extends RuleHandler {public void apply(Context context) {boolean allowed = activityService.isSupportedLocation(context.getLocation);if (allowed) {if (this.getSuccessor() != null) {this.getSuccessor().apply(context);}} else {throw new RuntimeException("非常抱歉,您所在的地区无法参与本次活动");}}
}

校验奖品是否已领完:

public class LimitRuleHandler extends RuleHandler {public void apply(Context context) {int remainedTimes = activityService.queryRemainedTimes(context); // 查询剩余奖品if (remainedTimes > 0) {if (this.getSuccessor() != null) {this.getSuccessor().apply(userInfo);}} else {throw new RuntimeException("您来得太晚了,奖品被领完了");}}
}

客户端:

public static void main(String[] args) {RuleHandler newUserHandler = new NewUserRuleHandler();RuleHandler locationHandler = new LocationRuleHandler();RuleHandler limitHandler = new LimitRuleHandler();// 假设本次活动仅校验地区和奖品数量,不校验新老用户locationHandler.setSuccessor(limitHandler);locationHandler.apply(context);
}

代码其实很简单,就是先定义好一个链表,然后在通过任意一节点后,如果此节点有后继节点,那么传递下去。

至于它和我们前面说的用一个 List 存放需要执行的规则的做法有什么异同,留给读者自己琢磨吧。

模板方法模式

在含有继承结构的代码中,模板方法模式是非常常用的。

通常会有一个抽象类:

public abstract class AbstractTemplate {// 这就是模板方法public void templateMethod() {init();apply(); // 这个是重点end(); // 可以作为钩子方法}protected void init() {System.out.println("init 抽象层已经实现,子类也可以选择覆写");}// 留给子类实现protected abstract void apply();protected void end() {}
}

模板方法中调用了 3 个方法,其中 apply() 是抽象方法,子类必须实现它,其实模板方法中有几个抽象方法完全是自由的,我们也可以将三个方法都设置为抽象方法,让子类来实现。也就是说,模板方法只负责定义第一步应该要做什么,第二步应该做什么,第三步应该做什么,至于怎么做,由子类来实现

我们写一个实现类:

public class ConcreteTemplate extends AbstractTemplate {public void apply() {System.out.println("子类实现抽象方法 apply");}public void end() {System.out.println("我们可以把 method3 当做钩子方法来使用,需要的时候覆写就可以了");}
}

客户端调用演示:

public static void main(String[] args) {AbstractTemplate t = new ConcreteTemplate();// 调用模板方法t.templateMethod();
}

代码其实很简单,基本上看到就懂了,关键是要学会用到自己的代码中。

状态模式

废话我就不说了,我们说一个简单的例子。商品库存中心有个最基本的需求是减库存和补库存,我们看看怎么用状态模式来写。

核心在于,我们的关注点不再是 Context 是该进行哪种操作,而是关注在这个 Context 会有哪些操作。

定义状态接口:

public interface State {
    public void doAction(Context context);
}

定义减库存的状态:

public class DeductState implements State {public void doAction(Context context) {System.out.println("商品卖出,准备减库存");context.setState(this);//... 执行减库存的具体操作}public String toString() {return "Deduct State";}
}

定义补库存状态:

public class RevertState implements State {public void doAction(Context context) {System.out.println("给此商品补库存");context.setState(this);//... 执行加库存的具体操作}public String toString() {return "Revert State";}
}

前面用到了 context.setState(this),我们来看看怎么定义 Context 类:(内部包含状态类State)

public class Context {private State state;private String name;public Context(String name) {this.name = name;}public void setState(State state) {this.state = state;}public void getState() {return this.state;}
}

我们来看下客户端调用,大家就一清二楚了:

public static void main(String[] args) {// 我们需要操作的是 iPhone XContext context = new Context("iPhone X");// 看看怎么进行补库存操作State revertState = new RevertState();revertState.doAction(context);// 同样的,减库存操作也非常简单State deductState = new DeductState();deductState.doAction(context);// 如果需要我们可以获取当前的状态// context.getState().toString();
}

读者可能会发现,在上面这个例子中,如果我们不关心当前 context 处于什么状态,那么 Context 就可以不用维护 state 属性了,那样代码会简单很多。

不过,商品库存这个例子毕竟只是个例,我们还有很多实例是需要知道当前 context 处于什么状态的。

行为型模式总结

行为型模式部分介绍了策略模式、观察者模式、责任链模式、模板方法模式和状态模式,其实,经典的行为型模式还包括备忘录模式命令模式等,但是它们的使用场景比较有限,而且本文篇幅也挺大了,我就不进行介绍了。

知识来源:

图文详解 23 种设计模式

相关文章:

java八股文面试[设计模式]——行为型模式

目录 策略模式 观察者模式 责任链模式 模板方法模式 状态模式 行为型模式关注的是各个类之间的相互作用&#xff0c;将职责划分清楚&#xff0c;使得我们的代码更加地清晰。 策略模式 策略模式太常用了 下面设计的场景是&#xff0c;我们需要画一个图形&#xff0c;可选…...

【送书活动】网络安全(黑客)自学

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…...

如何让数据成为企业的生产力?

为什么有的企业投入大量的人力、物力、财力做数字化转型建设最终做了个寂寞&#xff01;企业领导没看到数字化的任何价值&#xff01; 如果要问企业数字化转型建设最核心的价值体现是什么&#xff0c;大部分人都会说是&#xff1a;数据&#xff01; 然而&#xff0c;不同的人…...

监控 -- linux中的一些系统性能状态指令、Prometheus

目录 监控查看性能相关命令Prometheus1、安装和配置2、将 NFS服务器和LB服务器作为exporter采集数据3、在prometheus server里添加安装exporter程序的服务器 grafana出图工具 监控 监控的目的是获取数据&#xff0c;通过数据分析了解机器是否正常运行 查看性能相关命令 查看c…...

跳槽面试:如何转换工作场所而不失去优势

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

TINA如何导入spice模型

本文介绍如何使用TINA仿真运算放大器电路。TINA是TI公司自己的spice仿真软件&#xff0c;各个大厂为了更好的让客户使用自己的器件&#xff0c;都纷纷推出自己的仿真软件&#xff0c;ADI也有类似的软件&#xff0c;有机会我们介绍&#xff0c;这期我们主要简单介绍下如何使用TI…...

C. MEX Repetition Pinely Round 2 (Div. 1 + Div. 2)

Problem - C - Codeforces 题目大意&#xff1a;有一个长度为n的数组&#xff0c;数组中每个数字互不相同&#xff0c;范围都是0到n&#xff0c;每次操作将每一个数字从左到右依次变成当前数组的MEX&#xff0c;问k次操作后的数组 1<n<1e5&#xff1b;1<k<1e9 思…...

C++ 运算符

一键三连支持一下吧 C 运算符 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符&#xff0c;并提供了以下类型的运算符&#xff1a; 算术运算符关系运算符逻辑运算符位运算符赋值运算符杂项运算符 本章将逐一介绍算术运算符、关系运算符、逻辑…...

数据结构day07(栈和队列)

今日任务 链式队列&#xff1a; head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <stdlib.h>typedef int datatype; typedef struct link_list{datatype data;struct link_list* next; }link,*linkp; typedef struct circulate_line_t…...

八、Linux中的用户与文件权限

1、普通用户与特权用户 (1)在Linux中&#xff0c;和windows中一样。用户分为普通用户和特权用户。 特权用户&#xff1a;拥有系统管理的绝对权限。普通用户&#xff1a;普通用户的权限受到限制&#xff0c;只拥有基本的权限&#xff0c;某些操作没有权限。 (2)Linux中的特权…...

岛屿数量 -- 二维矩阵的dfs算法

岛屿数量 又被称为 FloodFill 算法 class NumIslands:"""floodFill 算法https://leetcode.cn/problems/number-of-islands/"""def solution(self, grid: List[List[str]]) -> int:res 0m, n len(grid), len(grid[0])for i in range(m):for…...

JDBC学习汇总

概念 JDBC&#xff1a;JDBC是Java提供的一套用来操作数据库的接口 通过Java代码操作数据库 1.确定数据库是可以正常使用&#xff08;MySQL服务是否正常开启&#xff09; 2.确定MySQL的账号和密码是正确的 3.确定MySQL版本和MySQL驱动版本匹配 4.在工程&#xff08;module&#…...

HarmonyOS—UI开发性能提升的推荐方法

注&#xff1a;本文转载自HarmonyOS官网文档 开发者若使用低性能的代码实现功能场景可能不会影响应用的正常运行&#xff0c;但却会对应用的性能造成负面影响。本章节列举出了一些可提升性能的场景供开发者参考&#xff0c;以避免应用实现上带来的性能劣化。 使用数据懒加载 开…...

英文科技论文写作与发表-常见英语写作困扰(第3章)

1.常见英语写作困扰 英语写作应该是越精炼越好。写完一个句子&#xff0c;建议尝试删除某个或某些单词&#xff0c;如果删除后句子意义基本不变&#xff0c;就应该删除。 1.1 所有格 使用所有格可以省去至少一个单词&#xff08;of&#xff09;,如&#xff1a;Kangs book T…...

video标签自动播放音视频并绘制波形图

html中的<video>标签可以用来播放常见的音视频格式&#xff0c;支持的格式包括:MP3、Ogg、WAV、AAC、MP4、WebM、AVI等&#xff0c;当然支持的格式也和浏览器和操作系统有关。这里以一个可以自动播放音视频并绘制波形图的页面为例说明一下<video>标签的用法。 vid…...

Netty—EventLoop

文章目录 一、EventLoopGroup 是什么&#xff1f;&#x1f914;️二、NioEventLoop 有哪些重要组成部分&#xff1f;&#x1f50d;三、NioEventLoop 的 thread 在何时启动&#xff1f;三、 run() 方法中线程在干嘛&#xff1f; 一、EventLoopGroup 是什么&#xff1f;&#x1f…...

[极客大挑战 2019]FinalSQL(bypass盲注)

这里是数字型注入&#xff0c;选择一个序号 fuzz ?id1这里过滤了很多东西 使用fuzzSQL字典&#xff0c;这是我自己定义编写的一个fuzz字典&#xff0c;内容较少 select from information . tables whereand " or | & union columns updatexml extractvalue databa…...

如何实现小程序与h5页面间的跳转

接到新需求&#xff0c;要在小程序页面内点击按钮实现跳转h5&#xff0c;一开始没接触过&#xff0c;还挺头疼的&#xff0c;但真正做起来&#xff0c;也就那么一回事啦&#xff0c;废话少说&#xff0c;直接上 1. 配置域名 先登录小程序开发平台&#xff0c;将页面需要跳转的…...

企业架构LNMP学习笔记9

nginx配置文件定义php-fpm服务&#xff1a; 编写测试文件&#xff1a; vim /usr/local/nginx/html/index.php 内容&#xff1a; <?phpphpinfo(); 在nginx的配置文件中配置&#xff1a; 修改配置文件&#xff0c;告知nginx如果收到.php结尾的请求&#xff0c;交由给php-…...

华为OD机试 - 二维伞的雨滴效应(Java JS Python)

题目描述 普通的伞在二维平面世界中,左右两侧均有一条边,而两侧伞边最下面各有一个伞坠子,雨滴落到伞面,逐步流到伞坠处,会将伞坠的信息携带并落到地面,随着日积月累,地面会呈现伞坠的信息。 1、为了模拟伞状雨滴效应,用二叉树来模拟二维平面伞(如下图所示),现在输…...

【HttpRunnerManager】搭建接口自动化测试平台操作流程

一、需要准备的知识点 1. linux: 安装 python3、nginx 安装和配置、mysql 安装和配置 2. python: django 配置、uwsgi 配置 二、我搭建的环境 1. Centos7 &#xff08;配置 rabbitmq、mysql 、Supervisord&#xff09; 2. python 3.6.8 &#xff08;配置 django、uwsgi&am…...

【C++】STL-常用算法-常用查找算法

0.前言 1.find #include <iostream> using namespace std;// 常用查找算法 find #include<vector> #include<algorithm>//查找 内置数据类型 void test01() {vector<int>v;for (int i 0; i < 10; i){v.push_back(i);}//查找 容器中 是否有 5 这个元…...

vue3 webpack打包流程及安装 (1)

npm run build 也可以打包 如果没有特殊需求 可以使用 效果其实是差不多的 --------------------------------------------------------------------------------------------------------------------------------- webpack网址 &#xff1a; 起步 | webpack 中文文档 (docsc…...

【C++】内联函数 ① ( 内联函数引入 | 内联函数语法 )

文章目录 一、内联函数引入1、内联函数引入2、代码示例 - 宏代码片段 与 内联函数 二、内联函数语法1、内联函数语法说明2、代码示例 - 内联函数基本语法 一、内联函数引入 1、内联函数引入 " 内联函数 " 是 C 语言中的一种特殊函数 , 其目的是为了提高程序的执行效率…...

聊聊springboot的ConfigurationProperties的绑定

序 本文主要研究一下springboot的ConfigurationProperties的绑定 ConfigurationPropertiesBindingPostProcessor org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java /*** {link BeanPostProcessor} to bind {link PropertySo…...

Mysql和Oracle的语法区别?

Mysql和Oracle是两种不同的关系型数据库。 MySQL通常在中小型应用程序、Web应用程序和小型企业中广泛使用&#xff0c;因为它易于学习和部署&#xff0c;而且成本较低。 Oracle数据库通常用于大型企业和复杂的企业级应用程序&#xff0c;因为它提供了高度可扩展性、高可用性…...

F - LIS on Tree

F - LIS on Tree (atcoder.jp) 问题描述&#xff1a;树上LIS。 普通LIS。O(n * n)。 void solve() {int n; cin>>n;vector<int> f(n 1),a(n1);for(int i 1; i < n; i) {cin>>a[i];f[i] 1;for(int j 1; j < i; j) {if(a[i] > a[j]) f[i] max…...

2023 年全国大学生数学建模B题目-多波束测线问题

B题目感觉属于平面几何和立体几何的问题&#xff0c;本质上需要推导几何变换情况&#xff0c;B题目属于有标准答案型&#xff0c;没太大的把握不建议选择&#xff0c;可发挥型不大。 第一问 比较简单&#xff0c;就一个2维平面的问题&#xff0c;但有点没理解&#xff0c;这个…...

qt creater11 翻译国际化教程教程:

先出效果图。 闲聊几句&#xff1a;qt这个翻译很方便&#xff0c;能直接导出项目里所有文字。 具体步骤如下&#xff1a; 在Qt中&#xff0c;我们可以使用QTranslator类来实现多语言切换。以下是一般步骤&#xff1a; 1. 在你的源代码中&#xff0c;所有需要翻译的字符串都…...

【AWS实验 】在 AWS Fargate 上使用 Amazon ECS 部署应用程序

文章目录 实验概览目标实验环境任务 1&#xff1a;连接到实验命令主机任务 2&#xff1a;将应用程序容器化任务 3&#xff1a;构建 Web2048 容器任务 4&#xff1a;创建 Amazon ECR 存储库并推送 Docker 映像任务 5&#xff1a;创建 ECS 集群任务 6&#xff1a;测试应用程序总结…...

选择锦州网站建设/网站是怎么做出来的

1.无外部包引用时用通常方法即可&#xff1b; 2.有外部包引用时&#xff0c;最好使用 fat jar eclipse plug-in&#xff0c;可以自己去下&#xff0c;zip文件解压后&#xff0c;将net.sf.fjep.fatjar_0.0.25文件夹放入eclipse的plugins文件 夹中&#xff0c;然后将里面的fatjar…...

如何将网站做成app/网站设计优化

练习 30 Else 和 if在上个练习中你学到了一些 if 语句&#xff0c;思考了它的含义和作用。在你学习更多内容之前&#xff0c;我会解释一下上个附加练习中的问题。首先确定你做了那些练习。1. 你认为 if 对它下面的代码起什么作用&#xff1f;if 语句在代码中创建了一个“分支”…...

网站建设收入的发票/网络营销案例范文

创建类的对象 类的实例化 实例化类 类和对象的使用&#xff08;面向对象思想落地的实现&#xff09;&#xff1a; 1.创建类&#xff0c;设计类的成员 2.创建类的对象 3.通过“对象.属性”或“对象.方法”调用对象的结构 如果创建了一个类的多个对象&#xff0c;则每个对象…...

wordpress 全站ssl/企业管理培训免费课程

ETL&#xff0c;是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;extract&#xff09;、转换&#xff08;transform&#xff09;、加载&#xff08;load&#xff09;至目的端的过程。最近在弄ETL方向的研究&#xff0c;到时也和大家…...

淄博做网站seo/搜狗收录提交入口

上一篇&#xff1a;基于MATLAB2018a的自动驾驶微观交通GUI仿真平台开发&#xff0c;及相关自动驾驶交通流的个人看法&#xff08;上&#xff09; - 一二三四的文章 - 知乎 一二三四&#xff1a;基于MATLAB2018a的自动驾驶微观交通GUI仿真平台开发&#xff0c;及相关自动驾驶交通…...

c语言也能干大事网站开发/武汉搜索推广

总体介绍 业务进行营销活动目的是用最少的钱实现更好的营销效果&#xff0c;此时就需要针对营销活动的资格进行控制&#xff0c;其中就包括了用户身份、用户所处的环境等等一系列因素的考虑&#xff0c;且为了防止恶意套取营销费用和做到营销效果的持续性&#xff0c;会进行活…...