【再探】设计模式—访问者模式、策略模式及状态模式

 访问者模式是用于访问复杂数据结构的元素,对不同的元素执行不同的操作。策略模式是对于具有多种实现的算法,在运行过程中可动态选择使用哪种具体的实现。状态模式是用于具有不同状态的对象,状态之间可以转换,且不同状态下对象的行为不同,客户端可以不必考虑其状态及转换,对所有的状态都可以执行同一的操作。

1 访问者模式

需求:需要对一个复杂数据结构进行操作,根据其不同的元素类型执行不同的操作。

1.1 访问者模式介绍

将数据结构与数据操作分离,通过定义一个访问者对象,来实现对数据结构中各个元素的访问和处理,从而达到解耦和灵活操作的目的。

图 访问者模式 UML

1.1.1 双分派

Java 是一种支持双分派的单分派语言。

单分派

调用哪个对象(多态)的方法,在运行期确定,调用对象的哪个方法,在编译期确定。

双分派

调用哪个对象(多态)的方法,在运行期确定,调用对象的哪个方法,在运行期确定。

图 单分派与双分派

访问者模式中的元素对象中的accept方法就是双分派。

public class VisitorPattern {public static void main(String[] args) {Element[] elements = {new MobilePhone(),new Ipad(),new Computer()};Visitor[] visitors = {new Student(),new Programmer()};for (Visitor visitor : visitors) {for (Element element : elements) {element.accept(visitor);}}}private interface Element {void accept(Visitor visitor);}private static class MobilePhone implements Element{@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public void makeCall() {System.out.println("打电话");}public void wechat() {System.out.println("微信聊天");}public void playGame() {System.out.println("玩王者荣耀");}}private static class Ipad implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public void watchTv() {System.out.println("刷剧");}public void playGame() {System.out.println("玩王者荣耀,大屏更爽");}}private static class Computer implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public void playGame() {System.out.println("玩电脑游戏:使命召唤");}public void work() {System.out.println("用于工作");}}private interface Visitor {void visit(MobilePhone mobilePhone);void visit(Ipad ipad);void visit(Computer computer);}private static class Programmer implements Visitor {@Overridepublic void visit(MobilePhone mobilePhone) {mobilePhone.makeCall();}@Overridepublic void visit(Ipad ipad) {ipad.playGame();}@Overridepublic void visit(Computer computer) {computer.work();}}private static class Student implements Visitor {@Overridepublic void visit(MobilePhone mobilePhone) {mobilePhone.wechat();}@Overridepublic void visit(Ipad ipad) {ipad.watchTv();}@Overridepublic void visit(Computer computer) {computer.playGame();}}}

1.2 优缺点

优点:

  1. 将数据结构与数据操作分离,当需要添加新的操作时,只添加新的子类即可,符合开闭原则。
  2. 将对元素的操作集中到一个类中,而不是分散在元素的子类中,使得职责更加明确,代码更加清晰,符合单一职责原则。

缺点:

  1. 不适合结构不稳定的数据结构,当新增或删除元素时,需要修改访问者类,不符合开闭原则。
  2. 如果访问者需要访问元素的内部信息,可能会破坏封装性。

2 策略模式

需求:一个算法有多种实现方式,或一个对象有很多的行为,这些行为需要使用多重条件选择语句来实现。期望把这些行为转移到具体的策略类中,避免使用难以维护的多重语句。

2.1 策略模式介绍

定义一个算法接口,然后将其不同的实现封装到具体的策略类中,并让它们可以相互替换。

图 策略模式 UML

public class StrategyPattern {public static void main(String[] args) {SortAlgorithm[] sortAlgorithms = {new BubbleSortAlgorithm(),new SelectionSortAlgorithm()};Integer[][] array = {{34,23,2,4,6,44,11,53,221,123},{3,66,27,212,45,565,11,44,33,12,465,55,22,14,56}};for (SortAlgorithm sortAlgorithm : sortAlgorithms) {for (Integer[] arr : array) {sortAlgorithm.sort(arr);}System.out.println();}}private static abstract class SortAlgorithm {public void sort(Integer[] array) { // 升序if (array != null && array.length > 1) {array = Arrays.copyOf(array,array.length);opera(array);System.out.println(Arrays.asList(array));}}protected abstract void opera(Integer[] array);}/*** 冒泡排序*/private static class BubbleSortAlgorithm extends SortAlgorithm{@Overrideprotected void opera(Integer[] array) {for (int i = 0; i < array.length; i++) {for (int j = i + 1; j < array.length; j++) {if (array[i] > array[j]) {int temp = array[j];array[j] = array[i];array[i] = temp;}}}}}/*** 选择排序*/private static class SelectionSortAlgorithm extends SortAlgorithm {@Overrideprotected void opera(Integer[] array) {for (int i = 0; i < array.length; i++) {int minPos = i;for (int j = i+1; j <array.length; j++) {if (array[minPos] > array[j]) {minPos = j;}}int temp = array[i];array[i] = array[minPos];array[minPos] = temp;}}}}

2.2 优缺点

优点:

  1. 符合开闭原则,增加新的算法或行为时只需要添加子类即可。
  2. 避免了多重条件选择语句。

缺点:

  1. 客户端必须知道所有的策略类,并自行决定使用哪个策略类。
  2. 会增加类的数量。

3 状态模式

需求:系统中某个对象存在多个状态,这些状态之间可以进行转换,且对象在不同状态下的行为不同。

3.1 状态模式介绍

将一个对象的状态从该对象中分离出来,封装到专门的状态类中。对于客户端而言,无须关心对象的状态及转换,无论对象处于哪种状态,客户端都可以一致性地处理。

图 状态模式 UML

public class StatePattern {public static void main(String[] args) {BackCard backCard = new BackCard();backCard.save(100);backCard.withdraw(1000);backCard.withdraw(600);backCard.withdraw(400);backCard.withdraw(100);}private static class BackCard {private final static State[] stateList = {new NormalState(),new Overdraft(),new LimitState()};private State state = stateList[0];private double balance = 0;public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}public void save(double money) {System.out.println("存钱操作:" + money);this.balance += money;changeState();}public void withdraw(double money) {System.out.println("取钱操作:" + money);try {state.withdraw(this,money);} catch (RuntimeException e) {System.out.println("取钱失败:" + e.getMessage());}changeState();}private void changeState() {System.out.println("-----余额:" + balance + "-----");if (balance >= 0) state = stateList[0];else if (balance >= -1000) state = stateList[1];else state = stateList[2];}}private interface State {void withdraw(BackCard backCard,double money);}private static class NormalState implements State {@Overridepublic void withdraw(BackCard backCard,double money) {backCard.setBalance(backCard.getBalance() - money);}}private static class Overdraft implements State {@Overridepublic void withdraw(BackCard backCard,double money) {if (money > 500) {throw new RuntimeException("卡被透支,取钱不能超过500元");}backCard.setBalance(backCard.getBalance() - money);}}private static class LimitState implements State {@Overridepublic void withdraw(BackCard backCard,double money) {throw new RuntimeException("卡被限制,不能取钱");}}}

3.2 优缺点

优点:

  1. 客户端可以不必关心对象的状态及转换,对所有状态都可进行同一操作。
  2. 将与具体状态相关的行为都封装在一个类中,符合单一职责原则,更容易扩展及维护。

缺点:

  1. 状态转换无论是在环境类还是状态类中,当增加新的状态或修改转换逻辑时,都需要修改转换代码,不符合开闭原则。
  2. 增加了类的个数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/19716.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用shell命令开启隧道转发的方式

1.适用场景 中转电脑可以通公网&#xff0c;也可以通内网&#xff0c;想把内网映射出去&#xff0c;公网其他电脑就可以通过该隧道远程访问内网的情况 2.命令 开隧道&#xff08;21235是自定义的转发端口&#xff09;&#xff1a; ssh -R 21235:内网地址:ssh端口 用户名公网服…

【C语言】基于C语言实现的贪吃蛇游戏

【C语言】基于C语言实现的贪吃蛇游戏 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C语言学习之路 文章目录 【C语言】基于C语言实现的贪吃蛇游戏前言一.最终实现效果一.Win32 API介绍1.1Win32 API1.2控制台程序1.3控制台屏幕上的坐标COORD…

编程学习 (C规划) 6 {24_4_18} 七 ( 简单扫雷游戏)

首先我们要清楚扫雷大概是如何实现的&#xff1a; 1.布置雷 2.扫雷&#xff08;排查雷&#xff09; &#xff08;1&#xff09;如果这个位置是雷就炸了&#xff0c;游戏结束 &#xff08;2&#xff09;如果不是雷&#xff0c;就告诉周围有几个雷 3.把所有不是雷的位置都找…

蓝桥杯单片机第五届国赛题目

前言&#xff1a;针对串口的练手&#xff0c;此处只作代码记录&#xff0c;不进行分析和展示 目录 题目代码底层驱动主程序核心代码 题目 代码 注&#xff1a;EEPROM的五组后丢弃用一个记录次数的变量进行循环即可&#xff0c;我没有写这一部分代码。 底层驱动 IIC unsign…

[深度学习]yolov10+deepsort+pyqt5实现目标追踪

YOLOv10DeepSORTPyQt5实现目标追踪系统 在现代智能监控系统中&#xff0c;目标追踪技术扮演着至关重要的角色。结合YOLOv10&#xff08;一种先进的实时目标检测算法&#xff09;与DeepSORT&#xff08;一种多目标追踪算法&#xff09;&#xff0c;并通过PyQt5构建用户界面&…

java——网络原理初识

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 目录 1.网络通信概念初识1.1 IP地址1.2端口号1.3协议1.3.1协议分层协议分层带来的好处主要有两个方面 1.3.2 TCP/IP五层 (或四层模型)1.3.3 协议的层和层之间是怎么配合工作的 1.网络通信概念初识…

再度“痛失”TOP5的小米手机,能否接好这碗AI“大活水”?

国产手机终端需求持续修复&#xff0c;国产品牌商是最大受益者。 近日&#xff0c;中国信通院发布2024年4月国内手机市场运行分析报告。报告显示&#xff0c;今年4月&#xff0c;国内市场手机出货量同比增长了28.8%。按品牌来看&#xff0c;国产品牌手机4月出货量占同期手机出…

港口利器:ModbusTCP转CAN轻松连接,提升跨运车效率!

BXKJ系列嵌入式通信模块&#xff0c;宛如一把神奇的钥匙&#xff0c;打开了与特定工业网络沟通的神秘之门。这些模块的可互换性&#xff0c;赋予了用户自由连接至任何所需网络的无限可能。它们与众多主流现场总线和工业以太网网络无缝对接&#xff0c;包括但不限于Profibus、De…

JVM哪些区域可能出现内存溢出,哪些地方需要GC?

GC顾名思义也就是垃圾回收&#xff0c;有人的地方就有江湖&#xff0c;那有数据的地方也理应有垃圾回收&#xff0c;所以思考一下&#xff0c;沿着之前提到过的JVM内存分区&#xff0c;堆&#xff0c;栈&#xff0c;程序计数器&#xff0c;方法区 堆、栈、方法区…

信息学奥赛初赛天天练-17-阅读理解-浮点数精准输出与海伦公式的巧妙应用

PDF文档公众号回复关键字:20240531 1 2023 CSP-J 阅读程序1 阅读程序&#xff08;程序输入不超过数组成字符串定义的范围&#xff1a;判断题正确填√&#xff0c;错误填&#xff1b;除特殊说明外&#xff0c;判断题1.5分&#xff0c;选择题3分&#xff0c;共计40分&#xff0…

C51单片机开发--库函数

知不足而奋进 望远山而前行 目录 系列文章目录 文章目录 前言 目标 内容 开发过程回顾 使用库函数点灯 什么是库函数? 面向库函数和面向寄存器开发 使用delay模块延时 总结 前言 在嵌入式系统开发中&#xff0c;使用库函数是提高开发效率、简化编程的重要手段之一…

Codeforces Round 949 (Div. 2) (A~C)

1981A - Turtle and Piggy Are Playing a Game 贪心&#xff0c;每次取x 2&#xff0c;求最大分数 // Problem: B. Turtle and an Infinite Sequence // Contest: Codeforces - Codeforces Round 949 (Div. 2) // URL: https://codeforces.com/contest/1981/problem/B // Me…

使用CS抓取WIN2012明文密码

目录 实验概述&#xff1a; 开始实验&#xff1a; 实验准备&#xff1a; 打开CS&#xff1a; 生成木马控制wind2012&#xff1a; 抓取明文密码&#xff1a; 实验概述&#xff1a; win2012及win10版本是不允许将明文密码储存在内存中的&#xff0c;此时我们…

【模型架构】学习RNN、LSTM、TextCNN和Transformer以及PyTorch代码实现

一、前言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;模型架构的不断发展极大地推动了技术的进步。从早期的循环神经网络&#xff08;RNN&#xff09;到长短期记忆网络&#xff08;LSTM&#xff09;、Transformer再到当下火热的Mamba&#xff08;放在下一节&a…

高并发项目-分布式Session解决方案

分布式Session解决方案 1.保存Session&#xff0c;进入商品列表页面 1.保存Session 1.编写工具类 1.MD5Util.java package com.sxs.seckill.utils;import org.apache.commons.codec.digest.DigestUtils;/*** Description: MD5加密工具类** Author sun* Create 2024/5/5 14…

云原生架构相关技术_1.容器技术

1.容器技术的背景与价值 容器作为标准化软件单元&#xff0c;它将应用及其所有依赖项打包&#xff0c;使应用不再受环境限制&#xff0c;在不同计算环境间快速、可靠地运行。容器部署模式与其他模式的比较如下图1所示。 图1 传统、虚拟化、容器部署模式比较 Docker容器基于操作…

形式参数和实际参数

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在调用函数时&#xff0c;大多数情况下&#xff0c;主调函数和被调用函数之间有数据传递关系&#xff0c;这就是有参数的函数形式。函数参数的作用是…

服务器怎么被远程桌面连接不上,远程桌面连接不上服务器的问题有效解决方案

远程桌面连接不上服务器是一个极其严重的问题&#xff0c;它可能直接影响到我们的工作效率、数据安全&#xff0c;甚至是整个业务运营的顺畅。因此&#xff0c;这个问题必须得到迅速且有效的解决。 当我们尝试远程桌面连接服务器时&#xff0c;可能会遇到连接不上的情况。这其中…

RxSwift - 实现一个MVVM架构的TableView

文章目录 RxSwift - 实现一个MVVM架构的TableView前沿MVVM架构的Tableview目录结构1、模型&#xff08;Model&#xff09;2、视图模型&#xff08;ViewModel&#xff09;3、视图&#xff08;View&#xff09; 界面效果 RxSwift - 实现一个MVVM架构的TableView 前沿 MVVM架构在…

redux状态管理用法详解

在React中使用redux&#xff0c;官方要求安装俩个其他插件 - Redux Toolkit 和 react-redux 1.ReduxToolkit (RTK) 官方推荐编写 Redux 逻辑的方式&#xff0c;是一套工具的集合集&#xff0c;简化书写方式 简化 store 的配置方式&#xff1b; 内置 immer 支持…