【Spring】设计模式(GOF)

Spring Framework在其架构和实现中广泛使用了多种GOF(Gang of Four)设计模式。这些设计模式帮助Spring解决了许多常见的软件开发问题,提高了代码的可重用性、可维护性和可扩展性。

1、工厂模式(Factory Pattern)

1.1简介

  • Spring使用工厂模式来管理bean的创建和实例化。
  • BeanFactory和ApplicationContext接口就是工厂模式的典型应用,它们负责根据配置信息或注解来创建和管理bean实例。
  • FactoryBean接口则是基于抽象工厂模式设计的,它允许用户自定义bean的创建逻辑。
  • 工厂模式有助于降低代码间的耦合度,并提高代码的可重用性和可扩展性。

1.2主要涉及角色

  • 抽象工厂(Abstract Factory):定义一个创建对象的接口,但不负责具体的对象创建过程。它通常是一个接口或者抽象类,其中定义了一个或多个创建对象的方法。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责实际创建具体的对象。每个具体工厂都对应着一种具体的对象类型。
  • 产品(Product):工厂所创建的对象类型。它可以是一个接口、抽象类或者具体类。
  • 具体产品(Concrete Product):实现产品接口的具体对象。

1.3代码示例

步骤一:

定义一个产品接口(例如Animal)

java 复制代码
public interface Animal {  
    void makeSound();  
}

步骤二:

创建实现该接口的具体类(例如Dog和Cat)

java 复制代码
public class Dog implements Animal {  
    @Override  
    public void makeSound() {  
        System.out.println("Woof woof!");  
    }  
}  
  
public class Cat implements Animal {  
    @Override  
    public void makeSound() {  
        System.out.println("Meow meow!");  
    }  
}

步骤三:

创建一个简单工厂类(例如AnimalFactory),该类负责创建Animal对象

java 复制代码
public class AnimalFactory {  
    // 静态方法,根据传入的类型参数返回相应的Animal对象  
    public static Animal createAnimal(String type) {  
        if ("dog".equalsIgnoreCase(type)) {  
            return new Dog();  
        } else if ("cat".equalsIgnoreCase(type)) {  
            return new Cat();  
        } else {  
            return null; // 或者抛出一个异常  
        }  
    }  
}

步骤四:

在客户端代码中使用这个工厂类来创建对象

java 复制代码
public class Main {  
    public static void main(String[] args) {  
        // 使用工厂类创建Dog对象  
        Animal dog = AnimalFactory.createAnimal("dog");  
        dog.makeSound(); // 输出: Woof woof!  
  
        // 使用工厂类创建Cat对象  
        Animal cat = AnimalFactory.createAnimal("cat");  
        cat.makeSound(); // 输出: Meow meow!  
  
        // 尝试创建一个不存在的动物类型,将返回null或抛出异常(取决于工厂类的实现)  
        Animal unknownAnimal = AnimalFactory.createAnimal("unknown");  
        if (unknownAnimal != null) {  
            unknownAnimal.makeSound();  
        } else {  
            System.out.println("Unknown animal type!");  
        }  
    }  
}

2、单例模式(Singleton Pattern)

2.1简介

  • 在Spring的默认作用域中,每个bean都是单例的,这意味着在整个应用程序的生命周期中,一个bean的ID只对应一个实例对象。

2.2应用场景

  • Windows的任务管理器、回收站等,只能有一个实例。
  • 计数器、配置管理、日志记录等需要全局唯一管理的类。
  • 数据库连接池、线程池等需要频繁创建和销毁的实例,使用单例模式可以节省开销。

2.3实现原理

单例模式的核心思想是将类的实例化过程控制在一个类中,避免其他类实例化该类对象。它通常通过以下步骤实现:

  • **私有化构造函数:**将类的构造函数私有化,防止外部类通过new关键字创建实例。
  • **创建静态实例:**在类中定义一个静态的私有实例,用于存储该类的唯一实例。
  • 提供全局访问点:通过提供一个静态的公共方法(通常是getInstance()方法),允许外部类访问该类的唯一实例。如果静态实例尚未创建,则在该方法中创建它。

2.4实现方式

在Java中,单例模式有多种实现方式,其中常见的有:

1、饿汉式(线程安全):

  • 在类加载时就已经完成了实例化,所以类加载较慢,但获取对象的速度快。
  • 代码示例如下
java 复制代码
public class Singleton {  
    private static Singleton instance = new Singleton();  
      
    private Singleton() {}  
      
    public static Singleton getInstance() {  
        return instance;  
    }  
}

2、懒汉式(线程不安全):

  • 在第一次调用getInstance()方法时才进行实例化,但这种方法在多线程环境下可能会产生多个实例。
  • 代码示例如下
java 复制代码
public class Singleton {  
    private static Singleton instance;  
      
    private Singleton() {}  
      
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

3、静态内部类实现

  • 利用JVM的类加载机制来保证初始化instance时只有一个线程,既线程安全又延迟加载。
  • 代码示例如下
java 复制代码
public class Singleton {  
    private Singleton() {}  
      
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
      
    public static Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}

4、枚举实现

  • 利用枚举的特性,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
  • 代码示例如下
java 复制代码
public enum Singleton {  
    INSTANCE;  
      
    // 其他方法...  
}

3、观察者模式(Observer Pattern)

3.1简介

  • Spring的事件驱动模型就是基于观察者模式实现的。
  • 当某个事件发生时,Spring会通知所有注册的观察者(即事件监听器)来执行相应的操作。
  • 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

3.2实现原理

  • **注册(Attach):**观察者将自己注册到主题中,以便在主题状态发生改变时收到通知。这通常通过调用主题的attach()或类似的方法来完成。
  • **通知(Notify):**当主题的状态发生改变时,它会遍历其观察者列表,并调用每个观察者的update()方法(或类似的方法)来通知它们。在调用update()方法时,主题通常会传递一些有关状态改变的信息给观察者。
  • **更新(Update):**观察者收到通知后,会根据主题传递的信息来更新自己的状态。这通常涉及重新计算值、更改用户界面或其他操作。

4、适配器模式(Adapter Pattern)

4.1简介

  • Spring MVC中的Controller适配器就是适配器模式的一个例子。
  • 它允许开发者使用不同类型的Controller来处理请求,而无需修改Spring MVC的核心代码。
  • 有目标接口(Target):客户端所期望的接口、适配者(Adaptee):需要被适配的类或者接口、适配器(Adapter):将适配者的接口转换成目标接口的类这三个主要角色

4.1实现方式

  • **类适配器:**适配器通过多重继承的方式实现目标接口,并继承适配者类。适配器中通常需要实现目标接口中定义的方法,并在这些方法中调用适配者的相关方法。
  • **对象适配器:**适配器通过持有一个适配者对象的引用来实现目标接口。适配器中同样需要实现目标接口中定义的方法,并在这些方法中调用适配者对象的相关方法。对象适配器通过组合的方式实现了适配,相对于类适配器更加灵活。

5、策略模式(Strategy Pattern)

5.1简介

  • Spring的事务管理机制就使用了策略模式。
  • 通过定义不同的事务管理策略(如编程式事务管理、声明式事务管理等),应用可以灵活地选择不同的事务处理方式。

5.2主要角色

  1. 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  2. 具体策略(ConcreteStrategy)角色:实现了抽象策略角色所定义的接口,封装了具体的算法或行为。
  3. 环境(Context)角色:持有一个策略对象的引用,并最终给客户端调用。

5.3实现步骤

  1. 定义策略接口(Strategy):定义一个接口或抽象类,用于封装算法。
  2. 实现具体策略类(ConcreteStrategy):创建实现了策略接口的实体类。
  3. 创建环境类(Context):该类中持有一个策略对象的引用,最终给客户端调用。

6、模板方法模式(Template Method Pattern)

6.1简介

  • Spring中的JdbcTemplate、HibernateTemplate等就是模板方法模式的实现。
  • 它们定义了一个算法的骨架,而将一些步骤延迟到子类中实现。
  • 模板方法模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。

6.2主要角色

  • 抽象类(Abstract Class):定义了一个或多个抽象操作和模板方法。这些抽象操作在抽象类中可能没有具体的实现,需要子类来实现。模板方法是一个具体的方法,它调用了一个或多个抽象操作。
  • 具体子类(Concrete Subclass):实现了抽象类中的抽象操作,这些操作在子类中可以有具体的实现。子类通过继承抽象类,并覆写其中的抽象操作来实现算法的特定步骤。

6.3实现步骤

  1. 定义抽象类:在抽象类中定义算法的框架,包括一个或多个抽象操作和模板方法。模板方法按照算法的顺序调用抽象操作。
  2. 实现具体子类:创建具体子类,继承抽象类,并覆写其中的抽象操作。这些覆写的方法将实现算法的特定步骤。
  3. 使用模板方法:在客户端代码中,创建具体子类的实例,并调用模板方法。模板方法会按照定义的顺序调用抽象操作,而抽象操作的具体实现在子类中定义。因此,算法的执行会根据子类的实现而有所不同。

7、代理模式(Proxy Pattern)

7.1简介

  • Spring AOP(面向切面编程)和Spring Security底层都使用了代理模式。
  • 通过代理对象来增强目标对象的功能,实现横切关注点(如事务、日志、安全等)的织入。

7.2主要角色

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

7.3分类

  • 静态代理:由程序员创建或工具生成代理类的源码,再编译代理类。静态代理在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
  • 动态代理:在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

8、装饰器模式(Decorator Pattern)

8.1简介

  • 装饰器模式允许向一个现有的对象添加新的功能,同时保持结构的开放性。
  • 在Spring中,这可以体现在通过配置文件或注解来动态地给bean添加新的行为或属性。

8.2主要角色

  • 抽象组件接口(Component):定义了一个接口,用于规范具体组件和装饰器对象的行为。
  • 具体组件类(ConcreteComponent):实现了抽象组件接口,是系统需要动态添加功能的对象。
  • 抽象装饰器类(Decorator):实现了抽象组件接口,并持有一个指向抽象组件对象的引用。装饰器类可以在其方法中调用被装饰对象的相应方法,并在其前后添加额外的功能。
  • 具体装饰器类(ConcreteDecorator):继承自抽象装饰器类,通过扩展抽象装饰器类的方法来实现具体的装饰功能。

8.3实现流程

  1. **定义组件接口,**包含原始对象和装饰器对象的共同操作。
  2. 创建具体组件类,实现组件接口的方法,提供基本功能。
  3. **创建装饰器类,**继承或实现组件接口,并持有一个组件对象的引用。
  4. 在装饰器类中,调用组件对象的方法,并在其前后添加额外的功能。
  5. 创建具体装饰器类,扩展装饰器类,并提供具体的功能扩展。
  6. 在客户端中,使用装饰器模式,通过组件接口操作装饰后的对象。

9、组合模式(Composite Pattern)

9.1简介

  • Spring本身并没有直接实现组合模式,但它的许多组件(如Bean容器、应用上下文等)都体现了组合模式的思想。这些组件可以包含其他组件,形成一个树形结构,从而支持递归组合和统一操作。

9.2主要角色

  • 抽象构件角色(Component):这是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。这个接口可以用来访问和管理所有的子对象。
  • 树枝构件角色(Composite):这是组合中的分支节点对象,表示具有子节点的对象。它实现了Component接口,并包含对子节点的引用。树枝构件可以包含其他树枝构件或叶子构件。
  • 树叶构件角色(Leaf):在组合树中表示叶节点对象,叶节点没有子节点。它实现了Component接口,但不需要包含对子节点的引用。
  • 客户角色(Client):通过Component接口操纵组合部件的对象。

9.3实现方式

  1. 定义抽象接口:首先定义一个包含公共方法的抽象接口(Component)。这个方法应该用于访问和管理Component子部件。
  2. 实现树枝构件和树叶构件:接着,创建实现Component接口的树枝构件(Composite)和树叶构件(Leaf)。树枝构件应该包含对子节点的引用,并实现与子节点相关的操作,如添加和删除子节点。树叶构件则不包含对子节点的引用。
  3. 创建客户角色:最后,创建客户角色(Client),该角色通过Component接口与组合对象进行交互。客户角色可以像处理单个对象一样处理组合对象,而无需关心其内部结构。
相关推荐
wang09076 分钟前
自己动手写一个spring之系列
spring
xieliyu.8 分钟前
Java算法精讲:双指针(二)
java·开发语言·算法
jeffer_liu33 分钟前
Spring AI 生产级实战:裁判员
java·人工智能·后端·spring·大模型
小bo波1 小时前
枚举实战
java·设计模式·枚举·后端开发·代码重构
夜微凉42 小时前
三、Spring
java·后端·spring
橘右今2 小时前
2026 Java后端高频面试宝典
java·开发语言·面试
xyzzklk3 小时前
解决Salesforce无法向外发送邮件
android·java·开发语言·网络·crm·salesforce·客户关系管理
biubiubiu07063 小时前
SpringBoot关于外部化配置
java·spring boot·spring
Full Stack Developme3 小时前
Spring Bean 依赖注入
python·spring·log4j
zzz_23683 小时前
【Spring】面试突击系列(二):SpringBoot 入门与自动配置原理
java·spring boot·spring