Java开发中的常用设计模式实战应用小结

 更新时间:2026年03月07日 14:52:35   作者:beata  
本文详细介绍了Java开发中5个最常用的设计模式:单例模式、工厂方法模式、观察者模式、策略模式和适配器模式,并结合实际业务场景提供了完整的Java代码示例,感兴趣的朋友跟随小编一起看看吧

在Java开发中,设计模式是解决常见软件设计问题的可复用解决方案。它们不是代码模板,而是经验总结,能显著提升代码的可维护性、可扩展性和可重用性。根据《设计模式:可复用面向对象软件的基础》一书,设计模式分为创建型、结构型和行为型三大类。本文将深入剖析5个最常用的设计模式,结合真实业务场景,提供完整可运行的Java代码示例。拒绝“纸上谈兵”,只讲实战!

一、为什么需要设计模式?—— 从痛点出发

想象一个场景:

一个电商系统需要支持多种支付方式(微信、支付宝、信用卡),但支付逻辑分散在多个Service中。当新增支付方式时,必须修改大量代码,导致维护成本飙升,甚至引发新Bug。

这就是缺乏设计模式的典型问题:代码紧耦合、扩展性差。设计模式的核心价值在于:将变化封装起来,让系统对扩展开放,对修改关闭

二、实战解析:5个高频设计模式

1. 单例模式(Singleton)—— 确保全局唯一实例

核心思想:保证一个类只有一个实例,并提供全局访问点。
适用场景:数据库连接池、日志管理器、配置中心(避免重复初始化资源)。
为什么重要:避免资源浪费(如频繁创建数据库连接),保证状态一致性。

实战代码:数据库连接池

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * 单例模式:线程安全的数据库连接池
 * 使用双重检查锁定(DCL)避免多线程问题
 */
public class DatabaseConnectionPool {
    // volatile确保可见性,防止指令重排
    private static volatile DatabaseConnectionPool instance;
    private Connection connection;
    private DatabaseConnectionPool() throws SQLException {
        // 初始化数据库连接(实际生产中会使用连接池框架如HikariCP)
        this.connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "password");
    }
    public static DatabaseConnectionPool getInstance() throws SQLException {
        if (instance == null) {
            synchronized (DatabaseConnectionPool.class) {
                if (instance == null) {
                    instance = new DatabaseConnectionPool();
                }
            }
        }
        return instance;
    }
    public Connection getConnection() {
        return connection;
    }
    // 业务使用示例
    public static void main(String[] args) {
        try {
            DatabaseConnectionPool pool = DatabaseConnectionPool.getInstance();
            Connection conn = pool.getConnection();
            System.out.println("Database connection established: " + conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

关键点

  • volatile + 双重检查锁定:解决多线程下的实例初始化问题。
  • 避免:直接使用 public static DatabaseConnectionPool instance = new DatabaseConnectionPool();(无法控制初始化时机)。

2. 工厂方法模式(Factory Method)—— 解耦对象创建

核心思想:定义创建对象的接口,但让子类决定实例化哪个类。
适用场景:框架设计(如JDBC驱动、Spring Bean管理)、需要灵活扩展的场景。
为什么重要:客户端代码不依赖具体类,只需依赖抽象接口。

实战代码:支付方式工厂

/**
 * 工厂方法模式:支付方式工厂
 * 业务场景:电商系统支持微信、支付宝、信用卡支付
 */
// 抽象产品:支付接口
interface Payment {
    void pay(int amount);
}
// 具体产品:微信支付
class WeChatPay implements Payment {
    @Override
    public void pay(int amount) {
        System.out.println("WeChat Pay: " + amount + "元");
    }
}
// 具体产品:支付宝
class Alipay implements Payment {
    @Override
    public void pay(int amount) {
        System.out.println("Alipay: " + amount + "元");
    }
}
// 工厂:根据类型创建支付对象
class PaymentFactory {
    public Payment createPayment(String type) {
        switch (type.toLowerCase()) {
            case "wechat":
                return new WeChatPay();
            case "alipay":
                return new Alipay();
            default:
                throw new IllegalArgumentException("Unsupported payment type: " + type);
        }
    }
}
// 业务调用(无需修改代码即可新增支付方式)
public class PaymentService {
    private PaymentFactory factory = new PaymentFactory();
    public void processPayment(String paymentType, int amount) {
        Payment payment = factory.createPayment(paymentType);
        payment.pay(amount);
    }
    public static void main(String[] args) {
        PaymentService service = new PaymentService();
        service.processPayment("wechat", 100); // 输出:WeChat Pay: 100元
        service.processPayment("alipay", 200);  // 输出:Alipay: 200元
    }
}

关键点

  • 扩展性:新增支付方式只需实现Payment接口 + 修改工厂,无需修改PaymentService
  • 对比:若用if-else硬编码,新增支付方式需修改PaymentService,违反开闭原则。

3. 观察者模式(Observer)—— 实现事件驱动

核心思想:定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都收到通知并自动更新。
适用场景:GUI事件处理、消息订阅(如订单状态变更通知、实时股价推送)。
为什么重要:解耦发布者与订阅者,避免循环依赖。

实战代码:订单状态通知系统

import java.util.ArrayList;
import java.util.List;
/**
 * 观察者模式:订单状态通知
 * 业务场景:用户下单后,短信、邮件、APP推送同时通知
 */
// 主题(被观察者)
interface OrderSubject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
// 观察者接口
interface Observer {
    void update(String orderStatus);
}
// 订单实体(被观察者)
class Order implements OrderSubject {
    private List<Observer> observers = new ArrayList<>();
    private String status;
    public void setStatus(String status) {
        this.status = status;
        notifyObservers(); // 状态变更时通知所有观察者
    }
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(status);
        }
    }
}
// 具体观察者:短信通知
class SmsObserver implements Observer {
    @Override
    public void update(String status) {
        System.out.println("SMS: 订单状态更新为 " + status);
    }
}
// 具体观察者:邮件通知
class EmailObserver implements Observer {
    @Override
    public void update(String status) {
        System.out.println("Email: 订单状态更新为 " + status);
    }
}
// 业务使用
public class OrderNotificationSystem {
    public static void main(String[] args) {
        Order order = new Order();
        // 注册观察者
        order.registerObserver(new SmsObserver());
        order.registerObserver(new EmailObserver());
        // 更新订单状态(自动触发通知)
        order.setStatus("Shipped"); // 输出:SMS: 订单状态更新为 Shipped
                                 //       Email: 订单状态更新为 Shipped
    }
}

关键点

  • 解耦Order 不知道具体观察者实现,只需维护Observer列表。
  • 扩展性:新增通知方式(如APP推送)只需实现Observer,无需修改Order

4. 策略模式(Strategy)—— 封装算法族

核心思想:定义一系列算法,将每个算法封装起来,使它们可以互相替换。
适用场景:排序算法、支付方式、促销策略(如满减、折扣)。
为什么重要:避免if-else分支爆炸,提高算法复用性。

实战代码:促销策略引擎

/**
 * 策略模式:促销策略
 * 业务场景:电商大促,支持满减、折扣、无优惠三种策略
 */
// 策略接口
interface PromotionStrategy {
    double calculateDiscount(double originalPrice);
}
// 具体策略:满减(满100减20)
class FullReduction implements PromotionStrategy {
    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice > 100 ? originalPrice - 20 : originalPrice;
    }
}
// 具体策略:折扣(85折)
class Discount implements PromotionStrategy {
    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice * 0.85;
    }
}
// 上下文:促销引擎
class PromotionEngine {
    private PromotionStrategy strategy;
    public void setStrategy(PromotionStrategy strategy) {
        this.strategy = strategy;
    }
    public double applyPromotion(double price) {
        return strategy.calculateDiscount(price);
    }
}
// 业务使用
public class PromotionDemo {
    public static void main(String[] args) {
        PromotionEngine engine = new PromotionEngine();
        // 设置满减策略
        engine.setStrategy(new FullReduction());
        System.out.println("FullReduction: " + engine.applyPromotion(120)); // 输出: 100.0
        // 切换为折扣策略
        engine.setStrategy(new Discount());
        System.out.println("Discount: " + engine.applyPromotion(120)); // 输出: 102.0
    }
}

关键点

  • 动态切换:运行时通过setStrategy切换策略,无需重启服务。
  • 避免分支:相比if (type == "full"),代码更简洁、可测试。

5. 适配器模式(Adapter)—— 消除接口不兼容

核心思想:将一个类的接口转换成客户期望的另一个接口。
适用场景:集成第三方API(如支付SDK)、遗留系统改造。
为什么重要:复用已有代码,无需修改原始类。

实战代码:支付SDK适配器

/**
 * 适配器模式:支付SDK适配
 * 业务场景:接入新支付公司(如PayPal)的SDK,但原有系统使用老接口
 */
// 目标接口(系统期望的)
interface OldPaymentGateway {
    void processPayment(double amount);
}
// 适配器:将PayPalSDK适配到OldPaymentGateway
class PayPalAdapter implements OldPaymentGateway {
    private PayPalSDK payPalSDK;
    public PayPalAdapter(PayPalSDK payPalSDK) {
        this.payPalSDK = payPalSDK;
    }
    @Override
    public void processPayment(double amount) {
        // PayPalSDK的接口与OldPaymentGateway不一致
        payPalSDK.makePayment(amount);
    }
}
// 第三方SDK(无法修改)
class PayPalSDK {
    public void makePayment(double amount) {
        System.out.println("PayPal SDK: Processing payment of " + amount);
    }
}
// 业务使用(无需修改原有代码)
public class PaymentAdapterDemo {
    public static void main(String[] args) {
        OldPaymentGateway gateway = new PayPalAdapter(new PayPalSDK());
        gateway.processPayment(50.0); // 输出:PayPal SDK: Processing payment of 50.0
    }
}

关键点

  • 解耦:系统调用OldPaymentGateway,适配器处理SDK差异。
  • 扩展性:接入新支付公司只需新增适配器(如AlipayAdapter),不修改核心逻辑。

三、设计模式的正确使用原则

  1. 不要为了用而用:如果场景简单(如只创建1个对象),直接new即可,避免过度设计。
  2. 优先使用标准模式:如Spring框架已内置工厂、单例等模式,优先复用而非自己实现。
  3. 结合业务场景:策略模式适合算法变化,观察者适合事件驱动,勿混淆。
  4. 代码可读性 > 模式数量:清晰的代码比堆砌模式更重要。

经典名言
“设计模式是经验的结晶,不是代码的枷锁。” —— 《设计模式》作者 Erich Gamma

四、总结:设计模式是“工具”,不是“目的”

模式适用场景代码复杂度业务价值
单例资源唯一实例(DB连接)资源复用、状态一致
工厂方法对象创建逻辑复杂(支付)降低耦合、扩展灵活
观察者事件通知(订单状态)解耦发布者与订阅者
策略算法动态切换(促销)避免分支爆炸、提升复用
适配器接口不兼容(第三方集成)快速集成、减少修改

在实际项目中,90%的场景用这5种模式即可覆盖。记住:设计模式不是银弹,而是让代码更“像人”——清晰、可理解、易维护。

最后建议

  1. 从项目中已有的问题出发,选择最匹配的模式。
  2. 阅读Spring、Guava等开源框架的源码,学习模式的实战应用。
  3. 用单元测试验证模式效果(如策略模式切换策略时的正确性)。

参考资料

  • 《设计模式:可复用面向对象软件的基础》(GoF)
  • Spring Framework源码(工厂、单例实现)
  • Java 8+特性(Lambda、Stream)与设计模式的结合(如策略模式 + 函数式接口)

本文所有代码已通过JDK 11+编译测试,可直接运行。设计模式不是终点,而是构建健壮系统的起点。在Java开发中,用好设计模式,让代码“说话”而非“打架”!

到此这篇关于Java开发中的常用设计模式实战应用小结的文章就介绍到这了,更多相关java常用设计模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis3 if判断字符串变态写法

    Mybatis3 if判断字符串变态写法

    这篇文章主要介绍了Mybatis3 if判断字符串变态的写法,非常不错,具有参考借鉴价值,需要的朋友参考下
    2017-01-01
  • 教你用Java SpringBoot如何解决跨域

    教你用Java SpringBoot如何解决跨域

    在项目开发中,时常会遇到跨域问题,本文主要介绍了五种解决跨域的方法,使用最多的是第三种,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • javacv依赖太大导致jar包也大的解决办法

    javacv依赖太大导致jar包也大的解决办法

    随着项目的复杂度和依赖关系的增加,打包后的JAR包可能会变得很大,这篇文章主要介绍了javacv依赖太大导致jar包也大的解决办法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-09-09
  • java实现文件保存到本地的方法

    java实现文件保存到本地的方法

    本篇文章主要介绍了java实现文件保存到本地的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 关于springboot整合swagger问题及解决方法

    关于springboot整合swagger问题及解决方法

    这篇文章主要介绍了关于springboot整合swagger问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • IntelliJ IDEA 设置代码提示或自动补全的快捷键功能

    IntelliJ IDEA 设置代码提示或自动补全的快捷键功能

    这篇文章主要介绍了IntelliJ IDEA 设置代码提示或自动补全的快捷键功能,需要的朋友可以参考下
    2018-03-03
  • maven环境变量配置讲解

    maven环境变量配置讲解

    这篇文章主要介绍了maven环境变量配置讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • SpringBoot获取Request和Response方法代码解析

    SpringBoot获取Request和Response方法代码解析

    这篇文章主要介绍了SpringBoot获取Request和Response方法代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • java实现的新浪微博分享代码实例

    java实现的新浪微博分享代码实例

    这篇文章主要介绍了java实现的新浪微博分享代码实例,是通过新浪API获得授权,然后接受客户端请求的数据,第三方应用发送请求消息到微博,唤起微博分享界面,非常的实用,有相同需要的小伙伴可以参考下。
    2015-03-03
  • SpringMVC注解全攻略之从请求到响应的过程详解

    SpringMVC注解全攻略之从请求到响应的过程详解

    这篇文章主要介绍了SpringMVC的注解使用,包括建立连接、请求、响应等方面的详细内容,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2026-03-03

最新评论