【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)

public interface Animal {  void makeSound();  
}

步骤二:

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

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对象

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; // 或者抛出一个异常  }  }  
}

步骤四:

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

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、饿汉式(线程安全):

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

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

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

3、静态内部类实现

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

4、枚举实现

  • 利用枚举的特性,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
  • 代码示例如下
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接口与组合对象进行交互。客户角色可以像处理单个对象一样处理组合对象,而无需关心其内部结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/18086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android14 WMS-窗口添加流程(一)-Client端

窗口布局在onCreate方法中通过setContentView(R.layout.xxx)加载,但窗口的显示并不是在wm_on_create_called中, 而是在wm_on_resume_called后,也就是说应用onResume时此窗口是不可见的,真正可见是当此window窗口的mDrawState变化状态从NO_SUR…

Raven2掠夺者2渡鸦2游戏预约注册教程 账号注册教程

《渡鸦2》是一款源自韩国的创新力作,作为《Raven》系列的最新续篇,这款游戏在MMORPG手游领域内再度扩展了其标志性的暗黑奇幻宇宙,融入了大量革新的游戏设计与丰富内容。定档于2024年5月29日开启公测的《渡鸦2》,正处在紧张刺激的…

blender复制uv贴图

1、新建两个猴头 2、点击其中一个进入uv编辑模式 3、在uv编辑中打开一个图像 4、新建一个材质球,将图像渲染到模型上 打开图像纹理 选择刚才打开的图像 切换到材质预览模式后,就可以看到贴图了 5、选择一个孤岛 6、然后选择拼排孤岛 可以看到该模型展开…

【全开源】JAVA人力资源招聘社会校招类型招聘系统校园招聘PC端

塑造企业高效招聘新体验 一、源码简介 招聘PC端源码,一款面向企业的招聘管理系统解决方案。它拥有完整的招聘流程管理功能,从职位发布到候选人管理,再到面试安排与结果反馈,所有环节都通过直观易用的界面进行展现,大…

Java面向对象-常用类(BigInteger类和BigDecemal类)

常用类-BigInteger类和BigDecemal类 使用 BigDecimal 进行计算时,我们不能再使用算术运算符(、-、*、/)进行算数运算,而是使用 BigDecimal 类提供的 add、subtract、multiply、divide 等方法来进行算数运算。 BigInteger: 能表示比…

考研408笔记总结~

目录 一.数据结构 二.计算机组成原理 三.操作系统 四.计算机网络 私以为边看视频,边做笔记会更专注些,大家需要自取。欢迎大家和我一起探讨考研的问题,包括不仅限于专业课,数学,英语等等......,想说什么…

Vivado打开之前项目仿真过的波形文件

第一步:顶部菜单 点击:Open Static Simulation 然后在弹出的窗口找到.sim结尾的文件夹,在里面找到wdb结尾的文件,点击ok 第二步:依次点击下方红圈 找到wcfg结尾的文件,点击ok即可

React:Mobx的autorun 和 runInAction(异步)

autorun 用法 监听变量变化 componentDidUpdate() {autorun(() > {console.log(this.list); // 每次 this.list 发生改变,都会触发这里// 对 list进行后续操作this.listChangeHandle();}) }⚠️注意 上边的autorun,会一直保留,每次组件加…

第十三届蓝桥杯国赛大学B组填空题(c++)

A.2022 动态规划 AC; #include<iostream> #define int long long using namespace std; int dp[2050][15]; //dp[i][j]:把数字i分解为j个不同的数的方法数 signed main(){dp[0][0]1;for(int i1;i<2022;i){for(int j1;j<10;j){//一种是已经分成j个数,这时只需每一个…

坦克飞机大战项目详解:从包结构到测试发布

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、项目初始化与包结构构建 代码案例&#xff1a; 二、资源文件与配置文件管理 代码案例…

MySQL简单测试和安装

MySQL 的特点 1、MySQL 性能卓越、服务稳定&#xff0c;很少出现异常宕机。 2、MySQL开放源代码且无版权制约&#xff0c;自主性及使用成本低。 3、MySQL历史悠久(版本众多)&#xff0c;用户使用活跃&#xff0c;遇到问题可以寻求帮助。 4、MySQL体积小(相对大型关系型数据库)…

linux安装mysql后,配置mysql,并连接navicate软件

Xshell连接登陆服务器 输入全局命令 mysql -u root -p 回车后&#xff0c;输入密码&#xff0c;不显示输入的密码 注意mysql服务状态&#xff0c;是否运行等 修改配置文件my.cnf&#xff0c;这里没找到就找my.ini&#xff0c;指定有一个是对的 find / -name my.cnf 接下…

Redis常用作MySQL等数据库的缓存层,如何保证Redis缓存和数据库数据的一致性?

1、写操作时&#xff1a;先更新数据库&#xff0c;再清除缓存&#xff1b; 2、读操作&#xff1a;读取缓存&#xff0c;存在则直接返回&#xff0c;不存在则读取数据库&#xff0c;之后更新到缓存。 为什么是删除缓存&#xff0c;而不是更新缓存呢&#xff1f; 更新缓存会有并…

【MySQL精通之路】SQL优化(1)

主博客&#xff1a; https://anakki.blog.csdn.net/article/details/139102441 1.优化SELECT语句 【MySQL精通之路】SQL优化(1)-查询优化-CSDN博客 2.优化子查询、派生表、视图引用和公用表表达式 3.优化INFORMATION_SCHEMA查询 4.优化Performance Schema查询 5.优化数据更改…

【Web】浏览器指纹:追踪用户的新技术

目录 什么是浏览器指纹&#xff1f;浏览器指纹的原理浏览器指纹的应用使用JavaScript获取浏览器指纹总结 在这个数字化时代&#xff0c;用户隐私和网络安全成为了人们日益关注的话题。而浏览器指纹作为一种追踪用户的新技术&#xff0c;正逐渐受到人们的关注。本文将详细介绍浏…

用BAT合并多个文件到一个文件中

加入有0001.txt,0002.txt,0003.txt三个文件&#xff0c;把这三个文件合并到all.txt文件的话&#xff0c; 把下面代码保存到“_mergeDelete.bat”中&#xff0c;双击运行即可。 &#xff08;应用场景&#xff1a;用VBA输出文件较大时&#xff0c;先进行拆分&#xff0c;最后把…

26计算机操作系统408考研--操作系统处理机调度篇章(五)

文章目录 一、调度简介死锁一、调度简介 计算机系统中,处理器和内存资源会出现供不应求的情况,特别是多个I/O设备与主机交互,作业不断进入系统,或者是多个批处理作业在磁盘的后备队列中等待进入内存的情况。操作系统在管理有限的资源的同时,需要考虑如何选取进入内存的作…

IS-IS开销值和协议优先级

原理概述 IS-IS 协议为路由器的每个 IS-IS 接口定义并维护了一个 Level-1开销值和一个 Level-2开销值。开销值可以在接口上或者全局上手动配置&#xff0c;也可以使用 Auto-Cost 自动计算确定。开销值的优先顺序为&#xff1a;接口上手动配置的开销值&#xff0c;全局上手动配置…

热门项目朋友聚会喝酒热场小游戏小程序源码系统 带完整的安装代码包以及搭建教程

系统概述 朋友聚会喝酒热场小游戏小程序源码系统是一款专门为朋友聚会场景设计的互动娱乐工具。它旨在为用户提供一系列有趣的小游戏&#xff0c;帮助提升聚会的氛围和趣味性&#xff0c;让朋友们在轻松愉快的环境中度过美好时光。本系统采用先进的技术架构&#xff0c;具备高…

TensorRT部署模型基本步骤(C++)

TensorRT部署模型基本步骤&#xff08;C&#xff09; 文章目录 TensorRT部署模型基本步骤&#xff08;C&#xff09;前言一、onnx模型转engine1.基于C代码生成engine2.基于trtexec.exe命令行生成 二、读取本地模型三、创建推理引擎四、创建推理上下文五、创建GPU显存缓冲区六、…