Spring中的设计模式

Spring中常用设计模式简单理解

一.Spring概述
1.Spring为了解决企业级应用开发的复杂性而创建的

2.Spring的最终使命:简化Java开发

3.Spring简化 Java开发采取的4中策略:
(1)基于POJO的轻量级和最小侵入性编程;
【这意味着,代码不过分的依赖框架,避免代码和框架绑死】
(POJO:Plain Ordinary Java Object,简单的Java对象(属性,getter,setter),实际就是普通JavaBeans)
(轻量级:Spring给用户提供的服务完全由用户自己决定,Spring想用什么服务自己开启使用。但是重量级的是只要你用就把所有的服务都给你,不能自己定制。)
(2)通过依赖注入和面向接口实现松耦合;
【使用第三方容器来管理各个数据模型之间的依赖,降低耦合性】
(3)基于切面和惯例进行声明式编程;
【便于系统模块的使用,只需要通过声明即可使用】
(4)通过切面和模板减少样板代码。

4.软件架构的设计原则(开口里合最单依)
(1)开闭原则
指一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。
(每次发生变化时,要通过添加新的代码来增强现有类型的行为,而不是修改原有的代码)
用抽象构建框架,用实现扩展细节
使用接口和抽象类

(2)依赖倒置原则
指设计代码结构时,高层模块不依赖底层模块,两者都依赖其抽象;抽象不依赖细节,细节依赖抽象。
针对接口编程,依赖于抽象而不依赖于具体

(3)单一职责原则
指不要存在多于一个导致类变更的原因
一个类,接口或方法只负责一项职责

(4)接口隔离原则
指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口

(5)迪米特原则(最少知道原则)
指一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的精合度。
一个实体应当尽量减少与其他实体之间发生相互作用,使得系统功能相对独立。
这样当一个模块修改时,影响的模块就会越少,扩展起来更加容易

(6)里氏替换原则
一个软件实体如果适用于一个父类,那么一定适用于其子类,所有引用父类的地方必须能够透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。
即子类可以扩展父类的功能,但不能改变父类原有的功能;任何基类出现的地方,子类一定可以出现。

(7)合成复用原则
尽量使用组合/聚合的方式,而不是使用继承。
继承叫做白箱复用,相当于把所有的实现细节暴露给子类;
组合/聚合称为黑箱复用,无法获取类以外的对象的实现细节。

二.Spring中常用的设计模式
创建型模式–>对象怎么来(创建对象的模式,对类的实例化进行抽象)
(一)工厂模式
1.简单工厂模式
适合对象较少的场景,客户端只需要传入工厂类的参数
不符合开闭原则优化(反射技术)优化可控性(参数运行时类)
【抽象产品,具体产品,工厂】
【Spring中:BeanFactory是简单工厂模式的体现】
2.工厂方法模式
 定义一个创建对象的接口(父类工厂),实现这个接口的类来实例化(子类具体工厂)
(也就是多态)
 具体的产品由不同的具体的工厂来创建
【抽象产品,具体产品,抽象工厂,具体工厂】
【Spring中:ApplicationContext及子类对工厂方法的使用】
3.抽象工厂模式
 抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一类
 缺点:产品族扩展困难,需要修改抽象工厂的接口
【抽象产品族,抽象产品,具体产品,抽象工厂,具体工厂】
(二)单例模式
【Spring中:scope为singleton的bean,用到了单例模式 ;获取时,使用了双重判断加锁机制】
实现一个类只有一个实例化对象&提供一个全局访问点
1 饿汉式单例模式
 类加载的时候就初始化(static),适用单例对象较少的情况
 依赖 JVM类加载机制,保证单例只会被创建1次,即 线程安全
 优点:没有任何锁,执行效率比较高
 缺点:类加载就初始化,用不用都占着,浪费内存
2. 懒汉式单例模式
 饿汉式:单例创建时机不可控,即类加载时自动创建单例
 懒汉式:单例创建时机可控,即有需要时,才手动创建单例
(1)同步锁
 使用同步锁 synchronized锁住创建单例的方法 ,防止多个线程同时调用,从而避免造成单例被多次创建
 缺点:每次访问都要进行线程同步(即调用synchronized锁),造成过多的同步开销(加锁 = 耗时、耗能)
(2)双重校验锁
 在同步锁的基础上,添加1层 if判断:若单例已创建,则不需再执行加锁操作就可获取实例,从而提高性能
 synchronized保证了线程安全,volatile禁止指令重排序保证了多线程获取时不为空
(3) 静态内部类
① 在静态内部类里创建单例,在装载该内部类时才会去创建单例
② 线程安全:类是由JVM加载,而JVM只会加载1遍,保证只有1个单例
3. 注册式单例模式
为了防止序列化对单例模式的破坏,适用注册式单例模式
(1)枚举式单例模式
 定义1个枚举的元素,即为单例类的1个实例
(2)容器式单例模式
 适用于实例非常多的情况,便于管理多个单例对象,但不是绝对线程安全的
4.基于ThreaLocal的单例模式(伪单例)
不能保证整个程序唯一;
可以保证线程唯一;
每个线程中拿到的实例都是一个;
不同的线程拿到的实例不是一个。
(三)原型模式
1.浅克隆
【Spring中:用户采用原型模式来创建新的Bean实例】
 浅克隆只是完整复制了值类型数据(8中基本数据类型),对于引用类型没有赋值,只是复制了引用类型对应的内存地址,所以引用还是指向原来的对象。
2.深克隆
 深克隆不仅能拷贝基本数据类型,还能拷贝引用类型(创建一个新的引用,不是指向原来的对象)
 JAVA中通过实现Cloneable和Serializable接口实现深克隆(重写clone方法,使用对象流将对象写入流然后读出)

结构型模式–>对象和谁有关(处理类和对象的组合)
(一)代理模式
 一个客户不想或者不能直接引用一个对象,可以通过代理对象在客户端和目标对象之间起到中介作用。
 角色:
① 抽象对象角色(顶层接口)
声明了目标对象和代理对象的共同接口,在任何可以使用目标对象的地方都可以使用代理对象
② 目标对象角色(被代理对象角色)
定义了代理对象所代表的目标对象
③ 代理对象角色
代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;
代理对象提供一个与目标对象相同的接口,以便可以在任何时候代替目标对象。

1.静态代理
 代理类和被代理类必须实现同一个接口
 静态代理只能对某个固定接口的实现类进行代理服务,其灵活性不强
2. 动态代理
 代理类在程序运行时创建的代理方式被成为动态代理
(1)JDK动态代理
 JDK代理要求被代理的类必须实现接口,有很强的局限性。
 因为Proxy动态产生的代理会调用InvocationHandler实现类,所以InvocationHandler是实际执行者
 Proxy.newProxyInstance(classLoader,interfaces,dynamicInvocationHandler)生成代理对象
 创建InvocationHandler接口实现类 重写invoke方法 实现具体的方法增强
 调用对象的方法最后都是调用InvocationHandler接口的invoke方法
 只能增强接口中有的方法、
 特点:底层使用反射机制进行方法的调用
(2)CGLIB动态代理
 返回并不要求只能是接口,类也可以
 CGLib会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)
 在CGLib底层,其实是借助了ASM这个非常强大的Java字节码生成框架。
 CHLib原理:
通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。由于是通过子类来代理父类,因此不能代理被final字段修饰的方法。
 优点:可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口
 特点:底层将方法全部存入一个数组中,通过数组索引直接进行方法调用
【Spring中:ProxyFactoryBean核心方法getObject中,主要调用getSingletonInstance和newPrototypeinstance】
【Spring中:Spring利用动态代理实现AOP时有两个非常重要的类:JdkDynamicAopProxy类和CglibAopProxy类,这两个类都实现了AopProxy接口】
(二)适配器模式
 在对象适配器模式中,适配器与适配者之间是关联关系;
 在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
【Spring中:Spring AOP中的AdvisorAdapter类,它有三个实现类:MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter和ThrowAdviceAdapter】
(三)装饰着模式
 在不必改变原类文件和使用继承的情况下,动态的扩展一个类的功能
【Spring中:Spring中的TransactionAwareCacheDecorator类用来处理事务缓存;MVC中,HttpHeadResponseDecorator类】

行为型模式–>对象与对象在干嘛(对在不同对象之间划分责任和算法的抽象化)
(一) 委派模式(不属于GoF的23种设计模式)
基本作用:负责任务的调用和分配
【Spring中:DispatcherServelet】
【Spring源码中:以Delegate结尾的地方都实现了委派模式】
(二)策略模式
 准备一组算法 & 将每一个算法封装起来,让外部按需调用 & 使得互换
 作用:
将算法的责任和本身进行解耦
1.算法可独立于使用外部而变化
2.客户端方便根据外部条件选择不同策略来解决不同问题
 策略模式仅仅封装算法(包括添加 & 删除),但策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定
【Spring中:Spring的初始化采用了策略模式,即不同类型的类采用不同的初始化策略,有一个InstantiationStrategy接口】
【Spring中:顶层的策略抽象有两种:SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy类】
(三)模板(方法)模式
 定义一个模板结构,将具体的内容延迟到子类中去实现
 模板模式是基于“继承”的
 提高代码复用性:
将相同部分的代码放在父类中,而将不同的代码放入不同的子类中
【Spring中:Spring中的JdbcTemplate】
(四)观察者模式
 对象之间一对多依赖,让多个观察者对象同时监听一个主体对象,主体对象发生变化时,所有观察者都会收到通知并更新
【Spring中:Spring中的ContextLoaderListener类实现了ServletContextListener接口,ServletContextListener接口又继承了EventListener接口】

你可能感兴趣的:(Java进阶,设计模式,spring)