Java 中的设计模式:经典与现代实践

Java 中的设计模式:经典与现代实践

1. 设计模式简介

设计模式是一种软件开发中的思想,它为我们提供了一些经过验证的、能够应对常见问题的解决方案。学习和掌握设计模式能够让开发者在面对复杂的需求时,能够设计出更加灵活、可维护的代码。现代 Java 语言的特点(如 Lambda 表达式Stream APIOptional)使得设计模式的实现更加简洁和高效。

设计模式按照其功能可以分为三大类:

  1. 创建型模式:用于对象创建,避免直接实例化。
  2. 结构型模式:用于类和对象的组合,解决系统中类之间的关系问题。
  3. 行为型模式:描述对象之间的交互和职责划分。

在这篇文章中,我们将通过现代 Java 的特性来重构经典设计模式的实现,帮助开发者更好地理解和运用设计模式。


2. 创建型设计模式

2.1 工厂模式(Factory Pattern)

经典实现

工厂模式通过封装对象的创建逻辑,将客户端与具体类的实例化解耦。通常适用于在创建对象时需要复杂逻辑或者希望通过参数控制生成不同对象的场景。

经典代码示例
// 产品接口
public interface Car {void drive();
}// 具体产品类
public class BMW implements Car {@Overridepublic void drive() {System.out.println("Driving BMW...");}
}public class Audi implements Car {@Overridepublic void drive() {System.out.println("Driving Audi...");}
}// 工厂类
public class CarFactory {public static Car createCar(String type) {switch (type.toLowerCase()) {case "bmw": return new BMW();case "audi": return new Audi();default: throw new IllegalArgumentException("Unknown car type");}}
}
现代 Java 实现:使用 Lambda 表达式

我们可以使用 Lambda 表达式来简化工厂模式的实现,减少冗长的 if-elseswitch 语句,使得代码更简洁、灵活。

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;public class CarFactory {private static final Map<String, Supplier<Car>> carRegistry = new HashMap<>();static {carRegistry.put("bmw", BMW::new);carRegistry.put("audi", Audi::new);}public static Car createCar(String type) {Supplier<Car> carSupplier = carRegistry.get(type.toLowerCase());if (carSupplier == null) {throw new IllegalArgumentException("Unknown car type");}return carSupplier.get();}
}
Spring 框架中的工厂模式

在 Spring 框架中,ApplicationContext 就是工厂模式的实现,它负责实例化并管理 Bean。

// Spring 通过工厂模式实例化 Bean
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = context.getBean("car", Car.class);
car.drive();

3. 结构型设计模式

3.1 代理模式(Proxy Pattern)

经典实现

代理模式通过引入代理对象来控制对真实对象的访问。代理对象可以在调用目标对象之前或之后增加额外的逻辑,比如日志、权限控制等。

经典代码示例
// 服务接口
public interface UserService {void createUser(String username);
}// 真实服务类
public class RealUserService implements UserService {@Overridepublic void createUser(String username) {System.out.println("Creating user: " + username);}
}// 代理类
public class UserServiceProxy implements UserService {private final RealUserService realUserService = new RealUserService();@Overridepublic void createUser(String username) {System.out.println("Logging: Start creating user");realUserService.createUser(username);System.out.println("Logging: End creating user");}
}
现代 Java 实现:使用 Java 8 的 StreamOptional

我们可以利用 Java 8 的 Optional 来避免 null 值的处理,并使用 Stream API 来简化数据的处理。

public class UserServiceProxy implements UserService {private final RealUserService realUserService = new RealUserService();@Overridepublic void createUser(String username) {Optional.of(username).filter(name -> !name.isEmpty()).ifPresentOrElse(name -> {System.out.println("Logging: Start creating user");realUserService.createUser(name);System.out.println("Logging: End creating user");},() -> System.out.println("Invalid username"));}
}
Spring AOP 中的代理模式

Spring 的 AOP(面向切面编程)就是利用代理模式来增强目标方法的功能。Spring 使用 JDK 动态代理CGLIB 代理 来生成代理对象。

@Service
public class OrderService {@Transactionalpublic void createOrder() {// 事务管理由代理类处理}
}

4. 行为型设计模式

4.1 策略模式(Strategy Pattern)

经典实现

策略模式通过定义一系列算法并将每个算法封装到独立的策略类中,使得算法的选择和使用变得灵活。策略模式能够在运行时动态地改变策略。

经典代码示例
public interface PaymentStrategy {void pay(int amount);
}public class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Paying " + amount + " using Credit Card");}
}public class PayPalPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Paying " + amount + " using PayPal");}
}public class PaymentContext {private PaymentStrategy strategy;public void setPaymentStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(int amount) {strategy.pay(amount);}
}
现代 Java 实现:使用 Stream 进行策略选择

可以通过 Stream API 来简化策略的选择过程,让代码更加简洁和优雅。

public class PaymentContext {private Map<String, PaymentStrategy> strategies = Map.of("credit", new CreditCardPayment(),"paypal", new PayPalPayment());public void executePayment(String paymentType, int amount) {Optional.ofNullable(strategies.get(paymentType)).ifPresentOrElse(strategy -> strategy.pay(amount),() -> System.out.println("Invalid payment method"));}
}
Spring 中的策略模式

Spring 中的 HandlerMapping 就是使用策略模式的一个例子,它通过不同的请求类型和处理器选择不同的处理策略。

public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

不同类型的 HandlerAdapter 处理不同的 Controller,如 SimpleControllerHandlerAdapter 处理 SimpleController


5. 模板方法模式(Template Method Pattern)

经典实现

模板方法模式通过定义一个算法的骨架,将某些步骤的实现延迟到子类中。这样,子类可以在保留算法结构的同时定制部分实现。

经典代码示例
public abstract class DataProcessor {public void process() {readData();processData();writeData();}protected abstract void readData();protected abstract void processData();protected abstract void writeData();
}public class CSVDataProcessor extends DataProcessor {@Overrideprotected void readData() {System.out.println("Reading CSV data...");}@Overrideprotected void processData() {System.out.println("Processing CSV data...");}@Overrideprotected void writeData() {System.out.println("Writing CSV data...");}
}
现代 Java 实现:使用 Lambda 表达式和 Optional

我们可以结合 Lambda 表达式 来动态传入处理步骤,让模板方法的使用更加灵活。

public abstract class DataProcessor {public void process() {processStep(this::readData, "Reading");processStep(this::processData, "Processing");processStep(this::writeData, "Writing");}private void processStep(Runnable step, String stepName) {System.out.println(stepName + " data...");step.run();}protected abstract void readData();protected abstract void processData();protected abstract void writeData();
}

6. 总结

通过结合现代 Java 特性,我们可以让经典的设计模式变得更加简洁和高效。 Lambda 表达式Stream API 为我们的设计模式实现提供了更灵活的方式,而 Optional 可以帮助我们避免空指针异常,使得代码更加健壮。

在实际的项目开发中,理解和运用设计模式能够大大提高代码的可维护性和可扩展性。希望本文的示例能够帮助你更好地理解设计模式,并在实际开发中灵活运用。

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

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

相关文章

windows下使用docker执行器并配置 hosts 解析

本篇目录 1. 问题背景2. 环境准备2.1 云上开通windows 2022 英文版机器2.1.1 安装 git2.1.2 安装 runner2.1.3 装docker2.1.4 注册runner并使用docker执行器 3. 项目信息3.1 编写window bat脚本3.2 项目.gitlab-ci.yml文件 4. 测试结论4.1 运行流水线 5. troubleshooting问题1&…

计算机毕业设计hadoop+spark视频推荐系统 短视频推荐系统 视频流量预测系统 短视频爬虫 视频数据分析 视频可视化 视频大数据 大数据

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

mysql的主从配置

#mysql数据库 #主从 MySQL数据库主从配置 1.MySQL主从介绍 MySQL 主从又叫做 Replication、AB 复制。简单讲就是 A 和 B 两台机器做主 从后&#xff0c;在 A 上写数据&#xff0c;另外一台 B 也会跟着写数据&#xff0c;两者数据实时同步的。 MySQL 主从是基于 binlog 的&…

MySQL、HBase、ES的特点和区别

MySQL&#xff1a;关系型数据库&#xff0c;主要面向OLTP&#xff0c;支持事务&#xff0c;支持二级索引&#xff0c;支持sql&#xff0c;支持主从、Group Replication架构模型&#xff08;本文全部以Innodb为例&#xff0c;不涉及别的存储引擎&#xff09;。 HBase&#xff1…

前端开发中的模拟后端与MVVM架构实践[特殊字符][特殊字符][特殊字符]

平时&#xff0c;后端可能不能及时给接口给前端进行数据调用和读取。这时候&#xff0c;前端想到进行模拟后端接口。本文将介绍如何通过vite-plugin-mock插件模拟后端接口&#xff0c;并探讨MVVM架构在前端开发中的应用。此外&#xff0c;我们还将讨论Vue2与Vue3的区别&#xf…

HTML5 新表单属性详解

HTML5 为 <form> 和 <input> 标签引入了一系列新属性&#xff0c;极大地增强了表单的功能和用户体验。这些新属性不仅简化了开发者的工作&#xff0c;还为用户提供了更友好、更高效的交互方式。本文将详细介绍这些新属性&#xff0c;并结合代码示例帮助大家更好地理…

SuperdEye:一款基于纯Go实现的间接系统调用执行工具

关于SuperdEye SuperdEye是一款基于纯Go实现的间接系统调用执行工具&#xff0c;该工具是TartarusGate 的修订版&#xff0c;可以利用Go来实现TartarusGate 方法进行间接系统调用。 该工具的目标是为了扫描挂钩的NTDLL并检索Syscall编号&#xff0c;然后使用它来执行间接系统调…

MySQL可直接使用的查询表的列信息

文章目录 背景实现方案模板SQL如何查询列如何转大写如何获取字符位置如何拼接字段 SQL适用场景 背景 最近产品找来&#xff0c;想让帮忙出下表的信息&#xff0c;字段驼峰展示&#xff0c;每张表信息show create table全部展示&#xff0c;再逐个粘贴&#xff0c;有点太耗费时…

HMV Challenges 022 Writeup

题目地址&#xff1a;https://hackmyvm.eu/challenges/challenge.php?c022 首先猜测是否为图片隐写&#xff0c;无果 盲猜图片上的小鸟是某种带符号的隐写 去这个网站找找看&#xff1a;https://www.dcode.fr/chiffres-symboles 找到了 参照原图片鸟儿的姿态选择并排放 所…

不建模,无代码,如何构建一个3D虚拟展厅?

在数字化浪潮的推动下&#xff0c;众多企业正积极探索线上3D虚拟展厅这一新型展示平台&#xff0c;旨在以更加生动、直观的方式呈现其产品、环境与综合实力。然而&#xff0c;构建一个既专业又吸引人的3D虚拟展厅并非易事&#xff0c;它不仅需要深厚的技术支持&#xff0c;还需…

【真机调试】前端开发:移动端特殊手机型号有问题,如何在电脑上进行调试?

目录 前言一、怎么设置成开发者模式&#xff1f;二、真机调试基本步骤&#xff1f; &#x1f680;写在最后 前言 edge浏览器 edge://inspect/#devices 谷歌浏览器&#xff08;开tizi&#xff09; chrome://inspect 一、怎么设置成开发者模式&#xff1f; Android 设备 打开设…

企业分类相似度筛选实战:基于规则与向量方法的对比分析

文章目录 企业表相似类别筛选实战项目背景介绍效果展示基于规则的效果基于向量相似的效果 说明相关文章推荐 企业表相似类别筛选实战 项目背景 在当下RAG&#xff08;检索增强生成&#xff09;技术应用不断发展的背景下&#xff0c;掌握文本相似算法不仅能够助力信息检索&…

校园网上店铺的设计与实现(代码+数据库+LW)

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统校园店铺商品销售信息管理难度大&#xff0c;容错率低&a…

基于springboot+vue的校园二手物品交易系统的设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

编译Android平台使用的FFmpeg库

目录 前言 一、编译环境 二、搭建环境 1.安装MSYS2 2.更新系统包 2.1 打开MSYS2 MinGW 64-bit终端&#xff08;mingw64.exe&#xff09; 2.2 更新所有软件包到最新版本 2.3 安装必要的工具和库。 3. 克隆FFmpeg源码 4. 配置编译选项 5. 执行编译 总结 前言 记录学习…

vim如何显示行号

:set nu 显示行号 :set nonu 不显示行号

揭开C++ 继承 的神秘面纱:深度剖析 类 的“血脉”传承

在C的面向对象编程中&#xff0c;继承&#xff08;Inheritance&#xff09;是实现代码复用和层次结构的重要特性。通过继承&#xff0c;新的类&#xff08;派生类&#xff09;可以从现有的类&#xff08;基类&#xff09;中继承属性和行为&#xff0c;从而减少重复代码&#xf…

翻译:How do I reset my FPGA?

文章目录 背景翻译&#xff1a;How do I reset my FPGA?1、Understanding the flip-flop reset behavior2、Reset methodology3、Use appropriate resets to maximize utilization4、Many options5、About the author 背景 在写博客《复位信号的同步与释放&#xff08;同步复…

基于微信小程序的设备故障报修管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

ue5 GAS制作一个技能

新建文件夹 ability 取名BP_BaseAbility 新建一个技能GAB_Melee 上面技能GAB_Melee和技能基类BP_BaseAbility 进入技能GAB_Melee&#xff0c;添加打印火云掌 给这个技能添加标签 点这个号 这样命名&#xff0c;小心这个点&#xff08;.&#xff09;作为分割 ability.ha…