Spring设计模式探幽(1)

本文探讨了Spring框架的设计初衷及简化Java开发的关键策略。通过分析Spring的核心接口BeanFactory,揭示了Spring如何利用工厂模式来实例化、配置和管理对象。此外,还详细对比了简单工厂、工厂方法和抽象工厂的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计伊始

  Spring 是为解决企业级应用开发的复杂性而设计,她可以做很多事。但归根到底支撑Spring的仅仅是少许的基本理念,而所有地这些的基本理念都能可以追溯到一个最根本的使命:简化开发。这是一个郑重的承诺,其实许多框架都声称在某些方面做了简化。

    而Spring则立志于全方面的简化Java开发。对此,她主要采取了4个关键策略:

        1,基于POJO的轻量级和最小侵入性编程;

        2,通过依赖注入和面向接口松耦合;

        3,基于切面和惯性进行声明式编程;

        4,通过切面和模板减少样板式代码;

    而他主要是通过:面向Bean、依赖注入以及面向切面这三种方式来达成的。
    而设计如此精妙的spring,其中肯定是有许多设计模式的,下面我们就通过阅读分析spring的源码来感受spring的密码。
     贴一个spring源码下载地址,下载托管在github了。
     https://github.com/spring-projects/spring-framework/tags
     我下的是spring3.2.5 release

常见的九种设计模式

分别是:简单工厂、工厂方法、单例模式、适配器模式、包装器模式、代理模式、观察者模式、策略模式、模板方法模式

1.工厂模式
org.springframework.beans.factory 这里是定义spring IOC容器接口的包,在这个包里有我们熟悉的BeanFactory 

package org.springframework.beans.factory;  

public interface BeanFactory {  

    /** 
     *这里是对FactoryBean的转义定义,如果使用bean的名字检索FactoryBean,得到的是工厂生成的对象,    
     *如果需要得到工厂本身,需要转义。For example, if the bean named 
     * <code>myJndiObject</code> is a FactoryBean, getting <code>&myJndiObject</code> 
     * will return the factory  
     */           
    String FACTORY_BEAN_PREFIX = "&";     

    /** 
     *这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。 
     */     
    Object getBean(String name) throws BeansException;     

    /** 
     *这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果 
     *根据名字取得的bean实例的Class类型和需要的不同的话。 
     */     
    Object getBean(String name, Class requiredType) throws BeansException;     

    /** 
    *这里提供对bean的检索,看看是否在IOC容器有这个名字的bean 
    */     
    boolean containsBean(String name);     

    /** 
     *这里根据bean名字得到bean实例,并同时判断这个bean是不是单例 
     */    
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;     

    /** 
     *这里得到bean实例的Class类型  
     */  
    Class getType(String name) throws NoSuchBeanDefinitionException;     

    /** 
     *这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来 
     */     
    String[] getAliases(String name);     
}  
  1. spring中BeanFactory和ApplicationContext的创建中都用到了典型的静态工厂模式。Bean 的创建采用了的工厂模式,他的顶级接口是 BeanFactory。BeanFactory 有三个子接口:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactor。这三个接口主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。这三个子接口集成了顶级接口并对BeanFactory的功能进行了增强,称为二级接口;ConfigurableBeanFactory对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry,可以被称为三级接口;ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,称为四级接口。其余的为抽象类,实现了Spring Bean四级接口所定义的所有功能。
    spring

一般来说采用BeanFactory的子接口ApplicationContext来创建BeanFactory的实例。ApplicationContext通常使用如下两个实现类:
FileSystemXmlApplicationContext:以基于文件系统的XML配置文件创建ApplicationContext实例。
ClassPathXmlApplicationContext:以类加载路径下的XML配置文件创建的ApplicationContext实例

public void testAC() {

        //1.在这里ApplicationContext接口继承了ListableBeanFactory, HierarchicalBeanFactory等二级接口

        ApplicationContext ac = new ClassPathXmlApplicationContext("cn/xyf/a_hello/applicationContext.xml");

        //2.从容器获取Bean
        User user = (User) ac.getBean("user");

        System.out.println(user);

    }
  • 在spring中,BeanFactory拥有类似的功能,它负责实例化、配置和管理对象。我们一般用的BeanFactory的实现类ApplicationContext,这个类会自动解析我们配置的applicationContext.xml,然后调用实现后的getBean方法然后根据我们配置的bean来new对象,将new好的对象放进一个容器中,键就是我们bean的id,值就是new的对象。

  • 在这里给出简单工厂模式的实现

//简单工厂模式
package cn.xyf.factory;

/**
 * @author Dale
 *  封装一个雷峰类
 */
public class LeiFeng {
    //扫地
    public void sweep(){
        System.out.println("扫地");
    }

    //洗衣
    public void wash(){
        System.out.println("洗衣");
    }

    //买米
    public void buyRice(){
        System.out.println("买米");
    }
}

//大学生子类
class UnderGraduate extends LeiFeng{

}

//社区志愿者子类
class Volunteer extends LeiFeng{

}


package cn.xyf.factory;

/**
 * @author Dale
 * 简单工厂模式
 */
public class SimpleFactory {
    //静态方法创建雷锋对象
    public static LeiFeng createLeiFeng(String type){
        LeiFeng result = null;
        switch(type){
            case "UnderGraduate":
                result = new UnderGraduate();
                break;
            case "UnderGrate":
                result = new Volunteer();
                break;
        }
        return result;
    }
}

package cn.xyf.factory;

/**
 * @author Dale
 * java 工厂模式
 */
public class Client {

    public static void main(String[] args) {
        //1.简单工厂模式  
        LeiFeng s1 = SimpleFactory.createLeiFeng("UnderGraduate");
        LeiFeng s2 = SimpleFactory.createLeiFeng("UnderGrate");
        s1.wash();
        s2.buyRice();

}
  • 在这里补充一下简单工厂、工厂、抽象工厂三者的区别

    1. 简单工厂
      简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。
      不修改代码的话,是无法扩展的。

    2. 工厂方法
      工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。
      在同一等级结构中,支持增加任意产品。

    3. 抽象工厂
      抽象工厂是应对产品族概念的。比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。
      应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。

  • 小结

★工厂模式中,重要的是工厂类,而不是产品类。产品类可以是多种形式,多层继承或者是单个类都是可以的。但要明确的,工厂模式的接口只会返回一种类型的实例,这是在设计产品类的时候需要注意的,最好是有父类或者共同实现的接口。

★使用工厂模式,返回的实例一定是工厂创建的,而不是从其他对象中获取的。

★工厂模式返回的实例可以不是新创建的,返回由工厂创建好的实例也是可以的。

区别

简单工厂 : 用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)

工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂 :用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)

以上三种工厂 方法在等级结构和产品族这两个方向上的支持程度不同。所以要根据情况考虑应该使用哪种方法。

### LSTM 的深入原理 LSTM 是一种特殊的循环神经网络(RNN),其设计目的是解决传统 RNN 中存在的梯度消失和梯度爆炸问题,从而能够捕捉长时间序列中的依赖关系。LSTM 通过引入门控机制以及细胞状态的概念实现了这一目标。 #### 细胞状态与门控结构 LSTM 的核心在于它的 **细胞状态** 和三个主要的门控单元:遗忘门、输入门和输出门。这些组件共同决定了信息如何流入、存储和流出 LSTM 单元。 1. **细胞状态(Cell State)** - 细胞状态是一个贯穿整个序列的信息流通道,它允许信息在整个序列中传递而不受太多干扰[^1]。 2. **遗忘门(Forget Gate)** - 遗忘门决定哪些信息应该从细胞状态中移除。该门接收当前输入 \(x_t\) 和前一时刻隐藏状态 \(h_{t-1}\),并通过一个 sigmoid 层计算出一个介于 0 到 1 之间的值,表示保留或丢弃的程度。 \[ f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f) \] 这里 \(W_f\) 表示权重矩阵,\(b_f\) 表示偏置向量,\(\sigma\) 表示激活函数sigmoid[^1]。 3. **输入门(Input Gate)** - 输入门控制新信息进入细胞状态的程度。这包括两个部分: - 使用另一个 sigmoid 层决定更新哪些部分。 \[ i_t = \sigma(W_i \cdot [h_{t-1}, x_t] + b_i) \] - 使用 tanh 层创建一个新的候选值向量,可能加入到状态中。 \[ \tilde{C}_t = \text{tanh}(W_C \cdot [h_{t-1}, x_t] + b_C) \] 4. **细胞状态更新** - 结合遗忘门和输入门的结果,更新细胞状态 \(C_t\)。 \[ C_t = f_t \odot C_{t-1} + i_t \odot \tilde{C}_t \] 其中 \(\odot\) 表示逐元素乘法操作[^1]。 5. **输出门(Output Gate)** - 输出门决定基于新的细胞状态输出什么值。首先通过一个 sigmoid 层确定输出的部分,再通过对细胞状态应用 tanh 函数得到最终输出。 \[ o_t = \sigma(W_o \cdot [h_{t-1}, x_t] + b_o) \] \[ h_t = o_t \odot \text{tanh}(C_t) \] #### 实现细节 以下是 Python 中使用 TensorFlow/Keras 构建基本 LSTM 型的代码示例: ```python import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense # 定义型架构 model = Sequential() model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features))) model.add(Dense(1)) model.compile(optimizer='adam', loss='mse') # 打印型概要 model.summary() ``` 在这个例子中,`LSTM` 层有 50 个单元,`activation='relu'` 设置了激活函数为 ReLU,而 `input_shape` 参数指定了输入数据的时间步数和特征数量[^1]。 尽管 LSTM 能够很好地处理长序列数据,但它也存在一些局限性。例如,在非常长的输入时间步长下,强迫 LSTM 记住单一观测可能会导致性能下降甚至失败[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值