深入解读五种常见 Java 设计模式及其在 Spring 框架中的应用

深入解读五种常见 Java 设计模式及其在 Spring 框架中的应用

1.1 设计模式简介

在软件开发过程中,设计模式 是一套针对常见问题的可复用解决方案。它们并非具体的代码片段,而是总结和提炼出的最佳实践,旨在提升代码的可读性可维护性扩展性

设计模式的核心思想在于封装变化抽象共性遵循开闭原则。掌握这些模式,不仅能够帮助开发者高效解决复杂业务场景,还可以更好地理解优秀框架(如 Spring、MyBatis 等)的设计思想。

1.2 设计模式分类

根据 "Gang of Four (GoF)" 设计模式理论,设计模式主要分为以下三类:

  • 创建型模式:控制对象创建的方式,隐藏复杂的实例化逻辑,提高代码的灵活性。
    • 常见模式:单例模式、工厂模式、建造者模式等。
  • 结构型模式:描述类和对象之间的组合关系,帮助系统更具模块化和松耦合性。
    • 常见模式:代理模式、适配器模式、装饰器模式等。
  • 行为型模式:描述对象间的交互方式和职责划分,提高系统的可扩展性和可维护性。
    • 常见模式:策略模式、模板方法模式、观察者模式等。
1.3 引出问题

在日常开发中,我们会遇到以下场景:

  • 需要动态创建不同类型的对象,而不暴露具体实现细节。
  • 为方法调用添加事务、安全检查或日志记录等功能,而不修改原始方法代码。
  • 使用不同的算法策略来处理不同类型的请求。

这些场景在复杂项目中非常普遍,因此,学习并掌握设计模式能够帮助开发者设计出更加优雅、健壮的代码架构。


2.1 工厂模式(Factory Pattern)

模式简介

工厂模式是创建型模式之一,它通过定义一个工厂类来负责创建对象,而不是由客户端直接实例化对象,从而实现对象创建与使用的解耦

模式结构
  • 产品接口:定义创建对象的标准接口或抽象类。
  • 具体产品类:实现产品接口,表示实际创建的对象。
  • 工厂类:封装对象的创建逻辑,对外提供方法创建不同类型的产品实例。
使用场景
  • 当对象的创建逻辑较为复杂时,通过工厂模式简化对象创建过程。
  • 当需要创建不同类型的对象,并根据参数或配置文件决定创建哪种对象时。
Java 示例代码

需求描述:一个汽车工厂可以创建不同类型的汽车(如 BMW、Audi)

java 复制代码
// 产品接口,定义汽车的行为
public interface Car {
    void drive();  // 驾驶方法
}

// 具体产品类:宝马车
public class BMW implements Car {
    @Override
    public void drive() {
        System.out.println("驾驶宝马汽车...");
    }
}

// 具体产品类:奥迪车
public class Audi implements Car {
    @Override
    public void drive() {
        System.out.println("驾驶奥迪汽车...");
    }
}

// 工厂类:封装创建逻辑
public class CarFactory {
    /**
     * 根据传入的类型创建汽车实例
     *
     * @param type 汽车类型(BMW或Audi)
     * @return 汽车实例
     */
    public static Car createCar(String type) {
        if ("BMW".equalsIgnoreCase(type)) {
            return new BMW();
        } else if ("Audi".equalsIgnoreCase(type)) {
            return new Audi();
        } else {
            throw new IllegalArgumentException("未知的汽车类型:" + type);
        }
    }
}
改进:加入配置化支持

如果希望可以通过配置文件修改汽车类型,可以使用 properties 文件来动态配置

java 复制代码
Properties properties = new Properties();
properties.load(new FileInputStream("carConfig.properties"));
String carType = properties.getProperty("car.type");
Car car = CarFactory.createCar(carType);  
car.drive();
在 Spring 框架中的应用

Spring 的 IOC 容器就是工厂模式的经典实现。Spring 容器通过 ApplicationContext 提供对象实例,而不需要手动创建对象:

java 复制代码
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = context.getBean("car", Car.class);
car.drive();  // 从容器中获取 Bean 实例,而非直接 new

在 Spring 代码中,BeanFactoryFactoryBean 也是工厂模式的具体实现:

java 复制代码
public class MyCarFactoryBean implements FactoryBean<Car> {
    @Override
    public Car getObject() {
        return new BMW();  // 工厂方法返回具体的 Car 实例
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }
}

2.2 单例模式(Singleton Pattern)

模式简介

单例模式确保一个类在整个应用程序中只有一个实例,并提供全局访问点。单例模式主要用于全局共享资源的管理。

模式结构
  • 唯一实例:类内部创建一个静态的唯一实例。
  • 私有构造方法 :防止外部通过 new 关键字创建新实例。
  • 全局访问方法:通过静态方法提供全局访问点。
使用场景
  • 配置管理类。
  • 日志管理类(如 Logger 类)。
  • 数据库连接池(只需要一个连接池实例)。
Java 示例代码

需求描述:实现一个单例类,保证实例唯一。

Java 示例代码
java 复制代码
public class Singleton {
    // 静态实例,保证全局唯一
    private static Singleton instance;

    // 私有构造方法,防止外部创建实例
    private Singleton() {
        System.out.println("创建单例实例...");
    }

    // 提供全局访问点
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();  // 第一次调用时创建实例
        }
        return instance;
    }
}
在 Spring 框架中的应用

Spring 默认的 Bean 是单例模式(scope="singleton"):

java 复制代码
<bean id="userService" class="com.example.UserService" scope="singleton" />

2.3 代理模式(Proxy Pattern)

模式简介

代理模式为其他对象提供代理对象,以控制对目标对象的访问。代理对象可以在方法调用前后 添加额外操作,例如权限检查事务控制日志记录等功能。

模式结构
  • 接口:定义目标对象需要实现的方法。
  • 真实对象:实现接口的方法,表示实际业务逻辑。
  • 代理对象:持有对真实对象的引用,添加额外操作。
使用场景
  • 事务管理:如在方法调用前开启事务,方法执行后提交事务。
  • 安全控制:如在方法调用前检查用户权限。
  • 缓存机制:如在方法调用后缓存结果,提高性能。
Java 示例代码

需求描述:通过代理类为服务类添加日志记录功能。

java 复制代码
// 服务接口
public interface UserService {
    void createUser(String username);
}

// 真实服务类,提供创建用户功能
public class RealUserService implements UserService {
    @Override
    public void createUser(String username) {
        System.out.println("创建用户:" + username);
    }
}

// 代理类,添加日志功能
public class UserServiceProxy implements UserService {
    private final RealUserService realUserService = new RealUserService();

    @Override
    public void createUser(String username) {
        System.out.println("日志记录:开始创建用户...");
        realUserService.createUser(username);
        System.out.println("日志记录:用户创建完毕!");
    }
}
在 Spring AOP 中的应用

Spring 使用动态代理机制实现 AOP,对方法调用进行拦截。例如,使用 @Transactional 注解时,Spring 在方法执行前后添加了事务管理逻辑:

java 复制代码
@Service
public class OrderService {
    @Transactional
    public void createOrder() {
        // 事务逻辑由代理类处理
    }
}

Spring 自动为 @Transactional 方法生成代理类,负责在方法调用前后开启和提交事务。


2.4 策略模式(Strategy Pattern)

模式简介

策略模式定义了一组可互换的算法策略,并将每个策略封装到独立类中。客户端通过上下文类在运行时选择不同的策略,从而实现算法的灵活切换。

模式结构
  • 策略接口:定义策略行为。
  • 具体策略类:实现具体算法逻辑。
  • 上下文类:持有策略对象,负责在运行时调用具体策略。
使用场景
  • 支付系统中,根据不同支付方式(如支付宝、微信、银行卡)选择不同的支付策略。
  • 文件处理系统中,根据文件类型选择不同的解析器(如 XML 解析器、JSON 解析器)。
Java 示例代码

需求描述:实现一个支付系统,支持不同的支付方式。

java 复制代码
// 策略接口
public interface PaymentStrategy {
    void pay(int amount);
}

// 具体策略类:信用卡支付
public class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("使用信用卡支付:" + amount + " 元");
    }
}

// 具体策略类:PayPal 支付
public class PayPalPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("使用 PayPal 支付:" + amount + " 元");
    }
}

// 上下文类
public class PaymentContext {
    private PaymentStrategy strategy;  // 当前使用的支付策略

    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void executePayment(int amount) {
        strategy.pay(amount);  // 调用具体支付策略
    }
}
在 Spring MVC 中的应用

Spring MVC 中的 HandlerAdapter 使用策略模式来处理不同类型的请求:

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

不同的 HandlerAdapter 实现类支持不同类型的 Controller,例如 SimpleControllerHandlerAdapter 处理 SimpleController


2.5 模板方法模式(Template Method Pattern)

模式简介

模板方法模式定义了一个算法的骨架,将具体实现延迟到子类。它允许子类在保留算法整体结构的同时重写具体步骤。

使用场景
  • 当多个子类有相似逻辑,但部分实现细节不同。
  • 数据处理系统中,文件读取、解析和写入的步骤固定,但文件格式不同。
Java 示例代码
java 复制代码
public abstract class DataProcessor {
    public void process() {
        readData();  // 读取数据
        processData();  // 处理数据
        writeData();  // 写入数据
    }

    protected abstract void readData();
    protected abstract void processData();
    protected abstract void writeData();
}

// CSV 数据处理类
public class CSVDataProcessor extends DataProcessor {
    @Override
    protected void readData() {
        System.out.println("读取 CSV 文件数据...");
    }

    @Override
    protected void processData() {
        System.out.println("解析 CSV 文件数据...");
    }

    @Override
    protected void writeData() {
        System.out.println("写入 CSV 文件数据...");
    }
}
在 MyBatis 中的应用

MyBatis 的 SqlSessionTemplate 是模板方法模式的典型应用,封装了 SQL 执行流程:

java 复制代码
sqlSessionTemplate.selectOne("namespace.method", parameter);

总结

通过上述设计模式的讲解,我们可以看到:

  • 工厂模式单例模式解决了对象创建问题。
  • 代理模式策略模式提高了系统的灵活性和可扩展性。
  • 模板方法模式在固定流程的场景中非常适用。

在实际项目中,合理运用设计模式能够显著提高代码质量,让系统更加灵活高效易维护。建议开发者在学习和实践中多关注常见框架中的设计模式应用,不断优化自己的代码设计能力。

相关推荐
CHANG_THE_WORLD10 分钟前
Linux 基础 6.进程
java·linux·运维
難釋懷30 分钟前
命令模式详解与应用
设计模式·命令模式
程序员谷美30 分钟前
Redis 性能优化:利用 MGET 和 Pipeline 提升效率
java·redis·性能优化
AI向前看31 分钟前
Perl语言的文件操作
开发语言·后端·golang
李匠202431 分钟前
Scala分布式语言二(基础功能搭建、面向对象基础、面向对象高级、异常、集合)
开发语言·后端·scala
Quantum&Coder37 分钟前
Dart语言的数据结构
开发语言·后端·golang
Heavydrink1 小时前
JSP内置对象、Servlet与MVC
java·servlet·mvc
雨 子1 小时前
Spring Web MVC
前端·spring boot·spring·mvc·postman
Lucky_Turtle1 小时前
【SpringSecurity】二、自定义页面前后端分离
java
雨 子1 小时前
SpringBoot环境和Maven配置
java·spring boot·后端·java-ee·maven