Java中的设计模式实战:单例、工厂、策略模式的最佳实践

article/2025/8/26 10:17:50

Java中的设计模式实战:单例、工厂、策略模式的最佳实践

在Java开发中,设计模式是构建高效、可维护、可扩展应用程序的关键。本文将深入探讨三种常见且实用的设计模式:单例模式、工厂模式和策略模式,并通过详细代码实例,展示它们的最佳实践。

单例模式:确保全局唯一性

单例模式是最简单的创建型模式之一,它确保一个类只有一个实例,并提供一个全局访问点。单例模式有多种实现方式,但每种方式都有其适用场景和注意事项。

懒汉式单例

懒汉式单例在类被加载时不会立即实例化,而是在第一次调用getInstance()方法时才创建实例,这样可以延迟初始化,节省资源。

public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

优点: 实现简单,按需初始化。

缺点: 每次调用getInstance()都需要进行同步,可能导致性能问题。

饿汉式单例

饿汉式单例在类加载时就立即实例化,确保了线程安全,但无法延迟初始化。

public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

优点: 简单且线程安全。

缺点: 无法延迟初始化,可能导致资源浪费。

双重检查锁定(DCL)单例

DCL单例结合了懒汉式和饿汉式的优点,既实现了延迟初始化,又保证了线程安全。

public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

优点: 实现了延迟初始化,且线程安全。

缺点: 代码相对复杂,需要理解volatile的语义。

最佳实践: 在大多数场景下,推荐使用DCL单例,因为它兼顾了性能和线程安全。

工厂模式:创建对象的抽象

工厂模式是一种创建型模式,它提供一个创建对象的接口,但让子类决定实例化哪个类。工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式。

简单工厂模式

简单工厂模式定义一个创建对象的类,由这个类来封装实例化的过程。

public class SocialMediaFactory {public static SocialMedia getService(String type) {if ("facebook".equals(type)) {return new FacebookService();} else if ("twitter".equals(type)) {return new TwitterService();} else {throw new IllegalArgumentException("Unknown type: " + type);}}
}interface SocialMedia {void connect();
}class FacebookService implements SocialMedia {public void connect() {System.out.println("Connecting to Facebook");}
}class TwitterService implements SocialMedia {public void connect() {System.out.println("Connecting to Twitter");}
}

优点: 将对象的创建逻辑集中在一个类中,便于维护。

缺点: 违反开闭原则,添加新类型需要修改工厂类。

工厂方法模式

工厂方法模式定义一个创建对象的接口,但让子类决定实例化哪个类。

abstract class SocialMediaFactory {abstract SocialMedia createService();
}class FacebookFactory extends SocialMediaFactory {@OverrideSocialMedia createService() {return new FacebookService();}
}class TwitterFactory extends SocialMediaFactory {@OverrideSocialMedia createService() {return new TwitterService();}
}

优点: 符合开闭原则,添加新类型只需添加新工厂类。

缺点: 需要为每个产品类型创建一个工厂类。

抽象工厂模式

抽象工厂模式提供一个创建一系列相关或依赖对象的接口,而不需要指定它们具体的类。

interface PaymentFactory {Payment createPayment();
}class CreditCardFactory implements PaymentFactory {@Overridepublic Payment createPayment() {return new CreditCardPayment();}
}class PayPalFactory implements PaymentFactory {@Overridepublic Payment createPayment() {return new PayPalPayment();}
}abstract class Payment {abstract void processPayment(double amount);
}class CreditCardPayment extends Payment {@Overridevoid processPayment(double amount) {System.out.println("Processing credit card payment of $" + amount);}
}class PayPalPayment extends Payment {@Overridevoid processPayment(double amount) {System.out.println("Processing PayPal payment of $" + amount);}
}

优点: 可以创建一系列相关对象,而无需指定具体类。

缺点: 系统中类的数量会显著增加。

最佳实践: 根据需求选择合适的工厂模式。如果对象创建逻辑简单,使用简单工厂;如果需要扩展性,使用工厂方法;如果需要创建一系列相关对象,使用抽象工厂。

策略模式:算法的灵活切换

策略模式是一种行为型模式,它定义一系列算法,把它们一个个封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

定义支付策略接口

public interface PaymentStrategy {void pay(double amount);
}

实现具体支付策略

public class CreditCardPayment implements PaymentStrategy {private String cardNumber;public CreditCardPayment(String cardNumber) {this.cardNumber = cardNumber;}@Overridepublic void pay(double amount) {System.out.println(amount + " paid with credit card " + cardNumber);}
}public class PayPalPayment implements PaymentStrategy {private String email;public PayPalPayment(String email) {this.email = email;}@Overridepublic void pay(double amount) {System.out.println(amount + " paid using PayPal " + email);}
}

使用策略上下文

public class ShoppingCart {private List<Item> items;private PaymentStrategy paymentStrategy;public ShoppingCart() {items = new ArrayList<>();}public void addItem(Item item) {items.add(item);}public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void checkout() {double total = calculateTotal();paymentStrategy.pay(total);items.clear();System.out.println("Order processed successfully!");}private double calculateTotal() {double total = 0;for (Item item : items) {total += item.getPrice() * item.getQuantity();}return total;}
}class Item {private String name;private double price;private int quantity;public Item(String name, double price, int quantity) {this.name = name;this.price = price;this.quantity = quantity;}public String getName() {return name;}public double getPrice() {return price;}public int getQuantity() {return quantity;}
}

客户端代码

public class Main {public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();cart.addItem(new Item("Book", 20, 1));cart.addItem(new Item("Laptop", 999, 1));// 使用信用卡支付cart.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456"));cart.checkout();// 切换到PayPal支付cart.setPaymentStrategy(new PayPalPayment("user@example.com"));cart.addItem(new Item("Mouse", 19.99, 1));cart.checkout();}
}

优点: 策略模式使算法可以独立于使用它的客户端而变化,提供了灵活的算法切换能力。

缺点: 需要为每个具体策略实现一个类,可能导致类数量增加。

最佳实践: 在需要动态切换算法或策略的场景中,优先考虑使用策略模式。例如支付方式选择、算法优化等场景。

总结

单例模式、工厂模式和策略模式是Java开发中非常实用的设计模式。单例模式确保全局唯一性,工厂模式抽象对象创建过程,策略模式提供算法的灵活切换能力。在实际项目中,合理运用这些设计模式,可以显著提高代码的可维护性和可扩展性。

记住,设计模式不是万能的,它们应该根据具体需求谨慎选择和使用。过度使用设计模式可能导致系统复杂度增加,反而降低开发效率。理解每种模式的适用场景,并在实际项目中根据需求灵活运用,是成为优秀Java开发者的必经之路。
在这里插入图片描述


http://www.hkcw.cn/article/kHHrBjSSne.shtml

相关文章

QT6搭建和使用MQTT

QT6搭建和使用MQTT 1.搭建MQTT环境1.下载源码2.CMake 编译 Qt MQTT 模块3.添加QT MQTT模块4.验证测试 2.MQTT的使用 1.搭建MQTT环境 1.下载源码 1.在GitHub下载对应qt版本的源码 git clone git://code.qt.io/qt/qtmqtt.git -b 6.5.3 这里以6.5.3版本的为例。 这里使用的是VS…

深入了解 C# 异步编程库 AsyncEx

在现代应用程序开发中&#xff0c;异步编程已经成为提升性能和响应能力的关键&#xff0c;尤其在处理网络请求、I/O 操作和其他耗时任务时&#xff0c;异步编程可以有效避免阻塞主线程&#xff0c;提升程序的响应速度和并发处理能力。C# 提供了内建的异步编程支持&#xff08;通…

使用 Azure DevOps 管道部署到本地服务器

Azure DevOps 是一个帮助改进 SDLC(软件开发生命周期)的平台。 在本文中,我们将使用 Azure Pipelines 创建自动化部署。 Azure DevOps 团队将 Azure Pipelines 定义为“使用 CI/CD 构建、测试和部署,适用于任何语言、平台和云平台”。 在这里,我将解释如何在 Azure Dev…

NSSCTF-[青海民族大学 2025 新生赛]wenshilou

下载附件得到jpeg图片 放到kali里面用binwalk命令进行分离 分离之后得到文件 点击zip文件里面有个flag&#xff0c;打开得到base64编码 直接放到随波逐流里面解码 得到flag NSSCTF{welcometoQinhaiminzudaxue}

React 编译器

&#x1f916; 作者简介&#xff1a;水煮白菜王&#xff0c;一位前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧和知识归纳总结✍。 感谢支持&#x1f495;&#x1f495;&#…

【机器学习基础】机器学习入门核心算法:K均值(K-Means)

机器学习入门核心算法&#xff1a;K均值&#xff08;K-Means&#xff09; 1. 算法逻辑2. 算法原理与数学推导2.1 目标函数2.2 数学推导2.3 时间复杂度 3. 模型评估内部评估指标外部评估指标&#xff08;需真实标签&#xff09; 4. 应用案例4.1 客户细分4.2 图像压缩4.3 文档聚类…

力扣热题100之二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 代码 方法一&#xff1a;递归 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightN…

【C++编程】C++学习笔记【更新ing】

C学习笔记 作者&#xff1a;齐花Guyc(CAUC) 文章目录 C学习笔记Chapter.1 面向对象编程&#xff08;OOP&#xff09;1.类&#xff08;class&#xff09;2.对象&#xff08;object&#xff09;3.封装&#xff08;Encapsulation&#xff09;4.继承&#xff08;Inheritance&#…

华为OD机试真题——矩形相交的面积(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

STM32F407VET6学习笔记7:Bootloader跳转APP程序

boot跳转APP的程序 目录 Flash分区设定&#xff1a; 工程文件地址设置&#xff1a; Bootloader工程文件&#xff1a; 测试的APP程序工程文件&#xff1a; Bootloader跳转程序&#xff1a; APP程序&#xff1a; Flash分区设定&#xff1a; 参考手册的分区&#xff1a; 工程文件…

5.29 打卡

DAY 39 图像数据与显存 知识点回顾 图像数据的格式&#xff1a;灰度和彩色数据模型的定义显存占用的4种地方 模型参数梯度参数优化器参数数据批量所占显存神经元输出中间状态 batchisize和训练的关系 作业&#xff1a;今日代码较少&#xff0c;理解内容即可 # 打印一张彩色图像…

关于scrapy在pycharm中run可以运行,但是debug不行的问题

关于scrapy在pycharm中run模式可以运行&#xff0c;但是debug模式不行的问题 文章目录 关于scrapy在pycharm中run模式可以运行&#xff0c;但是debug模式不行的问题查了下原因 点击run就可以运行&#xff0c;但是debug就是运行不了 一点击debug就报这个错&#xff0c;也不知道啥…

第7讲、Odoo 18 源码深度分析

Odoo 作为全球知名的开源 ERP 系统&#xff0c;其底层架构由众多核心 Python 文件共同支撑。本文将围绕 Odoo 18 版本中 的 api.py、exceptions.py、fields.py、http.py、loglevels.py、models.py、netsvc.py、release.py、sql_db.py 等关键文件&#xff0c;进行源码结构与实现…

【春秋云镜】CVE-2022-26965 靶场writeup

知识点 网站的主题或者模块位置一般是可以上传文件的&#xff0c;不过一般为压缩包形式主题或者模块可以上github上找到和cms匹配的源码主题被解压后会放到加入到对应的文件夹中&#xff0c;而且还会自动执行对应的info.php文件(需要主题和cms配套才行)我这里取巧了&#xff0…

JUC多线程核心知识点深度解析

最近正在复习Java八股&#xff0c;所以会将一些热门的八股问题&#xff0c;结合ai与自身理解写成博客便于记忆 本文将从以上10个经典面试问题来做juc多线程的解析 一、线程状态与流转机制 1. 六种线程状态&#xff08;Java定义&#xff09; public enum State {NEW, …

设计模式学习笔记

设计模式 一&#xff1a;分类&#xff1a; 创建型模式 用于描述“怎样创建对象”&#xff0c;它的主要特点是“将对象的创建与使用分离”。GoF&#xff08;四人组&#xff09;书中提供了单例、原型、工厂方法、抽象工厂、建造者等 5 种创建型模式。 结构型模式 用于描述如何将…

【地图】腾讯地图页面卡顿问题解决

目录 背景问题排查解决1. 页面是否使用 keep-alive 进行路由缓存2. 离开地图页面时&#xff0c;是否将地图清除 总结 背景 有的电脑没有显卡会出现如下问题&#xff1a; 系统打开有地图的页面&#xff0c;CPU 占用直线飙升到100%下不来&#xff0c;切到非地图页面&#xff0c;C…

一起看 I/O | Android 性能相关最新动态

作者 / Ben Weiss 过去几年来&#xff0c;我们一直致力于让性能提升工作变得更易上手、回报更高。我们将在本文中分享这一领域的最新发展动态。为您介绍基准配置文件、Android Studio 中的工具改进、库&#xff0c;以及我们如何让这项技术更好地在后台为您服务。此外&#xff0…

iPhone批量删除照片的方法

对于每一个iPhone用户来说&#xff0c;照片管理是一项日常而重要的任务。随着时间的积累&#xff0c;无数的照片快速填满了我们的存储空间&#xff0c;从美丽的风景到重要的家庭聚会&#xff0c;每一张照片都记录着我们生活中的瞬间。然而&#xff0c;当存储空间即将耗尽时&…

Gradle Kotlin 规范插件用于模块化结构 - 共享构建逻辑

Gradle Kotlin 规范插件用于模块化结构 - 共享构建逻辑 我们中的许多人都遇到过Groovy的困难&#xff0c;并习惯于将其转换为Kotlin DSL。 然后&#xff0c;作为Android工程师&#xff0c;在完全使用Kotlin编写的项目上工作是纯粹的喜悦。 我们假设采用基于功能的模块化应用程…