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


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

想象一个场景:

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


二、实战解析: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. 代码可读性 > 模式数量:清晰的代码比堆砌模式更重要。

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

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

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


参考资料

  • 《设计模式:可复用面向对象软件的基础》(GoF)
  • Spring Framework源码(工厂、单例实现)
  • Java 8+特性(Lambda、Stream)与设计模式的结合(如策略模式 + 函数式接口)
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com