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

2024-06-01 00:28

本文主要是介绍【再探】设计模式—访问者模式、策略模式及状态模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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.chinasem.cn/article/1019466

相关文章

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

MySQL设置密码复杂度策略的完整步骤(附代码示例)

《MySQL设置密码复杂度策略的完整步骤(附代码示例)》MySQL密码策略还可能包括密码复杂度的检查,如是否要求密码包含大写字母、小写字母、数字和特殊字符等,:本文主要介绍MySQL设置密码复杂度... 目录前言1. 使用 validate_password 插件1.1 启用 validate_passwo

C#和Unity中的中介者模式使用方式

《C#和Unity中的中介者模式使用方式》中介者模式通过中介者封装对象交互,降低耦合度,集中控制逻辑,适用于复杂系统组件交互场景,C#中可用事件、委托或MediatR实现,提升可维护性与灵活性... 目录C#中的中介者模式详解一、中介者模式的基本概念1. 定义2. 组成要素3. 模式结构二、中介者模式的特点

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

SpringBoot中4种数据水平分片策略

《SpringBoot中4种数据水平分片策略》数据水平分片作为一种水平扩展策略,通过将数据分散到多个物理节点上,有效解决了存储容量和性能瓶颈问题,下面小编就来和大家分享4种数据分片策略吧... 目录一、前言二、哈希分片2.1 原理2.2 SpringBoot实现2.3 优缺点分析2.4 适用场景三、范围分片