Spring常用的设计模式

目录

一、六大设计原则

二、23 种设计模式(按类型分类)

1. 创建型模式(5 种):处理对象创建,隐藏创建逻辑

2. 结构型模式(7 种):处理类或对象的组合,优化结构

3. 行为型模式(11 种):处理对象间交互,优化行为协作

三、设计原则与模式的关系

四、常用的设计模式

1、单例模式

2、工厂模式

3、模板模式

4、代理模式

1、含义:

2、作用

3、代理模式

1、静态代理

2、动态代理(动态代理是在程序运行时通过反射机制动态创建的。)


一、六大设计原则

  1. 单一职责原则(Single Responsibility Principle)
    • 一个类只负责一项职责,仅有一个引起它变化的原因。
    • 例:用户类(User)只管理用户信息,不应包含订单处理逻辑(应交给订单类)。
  1. 开放 - 封闭原则(Open-Closed Principle)
    • 对扩展开放(可新增功能),对修改关闭(不改动原有代码)。
    • 例:通过接口定义支付行为(IPay),新增 “支付宝” 支付时只需实现接口,无需修改原有支付流程。
  1. 里氏替换原则(Liskov Substitution Principle)
    • 子类可替换父类,且替换后不改变原有程序的正确性。
    • 反例:正方形类继承长方形类,修改正方形的 “宽” 会同时改变 “长”,违反长方形的逻辑。
  1. 接口隔离原则(Interface Segregation Principle)
    • 避免 “臃肿接口”,应拆分为多个专用接口,客户端只需依赖所需接口。
    • 例:将 “动物接口” 拆分为 “会飞接口”“会跑接口”,鸟实现前者,狗实现后者。
  1. 依赖倒置原则(Dependency Inversion Principle)
    • 依赖抽象(接口 / 抽象类),而非具体实现;高层模块不依赖低层模块。
    • 例:服务层依赖 IUserDao 接口,而非具体的 MysqlUserDaoOracleUserDao
  1. 迪米特法则(Law of Demeter)
    • 一个对象应尽可能少地了解其他对象(只与直接朋友通信)。
    • 例:学生类无需直接操作课程的数据库访问,应通过 “班级管理类” 间接获取课程信息。

二、23 种设计模式(按类型分类)

1. 创建型模式(5 种):处理对象创建,隐藏创建逻辑
  • 单例模式(Singleton)
    确保类只有一个实例,并提供全局访问点。
    应用:Spring 的 Bean 默认单例、日志工具类。
  • 工厂方法模式(Factory Method)
    定义创建对象的接口,由子类决定实例化哪个类。
    应用:Spring 的 BeanFactory(通过不同实现类创建不同类型的 Bean)。
  • 抽象工厂模式(Abstract Factory)
    提供一个接口,用于创建一系列相关 / 依赖对象,无需指定具体类。
    应用:数据库访问层(同时创建 Connection、Statement 等配套对象)。
  • 建造者模式(Builder)
    分步构建复杂对象,分离对象的构建与表示。
    应用:StringBuilder、 Lombok 的 @Builder 注解。
  • 原型模式(Prototype)
    通过复制现有对象创建新对象(避免重复初始化)。
    应用:Spring 的 Bean 作用域(prototype 原型模式)。
2. 结构型模式(7 种):处理类或对象的组合,优化结构
  • 适配器模式(Adapter)
    将一个类的接口转换为客户端期望的另一个接口,解决兼容性问题。
    应用:InputStreamReader(将字节流适配为字符流)。
  • 装饰器模式(Decorator)
    动态给对象添加功能,不改变原有类结构。
    应用:BufferedInputStream(为输入流添加缓冲功能)。
  • 代理模式(Proxy)
    为对象提供代理,控制对原对象的访问(如权限、延迟加载)。
    应用:Spring AOP 动态代理、MyBatis 的 Mapper 代理。
  • 外观模式(Facade)
    提供一个统一接口,简化复杂系统的调用。
    应用:电脑启动(只需调用 “启动” 方法,内部自动处理 CPU、内存、硬盘初始化)。
  • 桥接模式(Bridge)
    将抽象与实现分离,使两者可独立变化。
    应用:图形界面(形状抽象类与渲染实现类分离,可分别扩展)。
  • 组合模式(Composite)
    树形结构中,统一处理单个对象和组合对象。
    应用:文件夹结构(文件和文件夹统一视为 “节点” 操作)。
  • 享元模式(Flyweight)
    复用细粒度对象,减少内存消耗(共享不变部分)。
    应用:字符串常量池(相同字符串复用同一对象)。
3. 行为型模式(11 种):处理对象间交互,优化行为协作
  • 策略模式(Strategy)
    定义算法族,动态选择使用哪种算法(消除大量 if-else)。
    应用:电商折扣系统(不同会员等级对应不同折扣策略)。
  • 模板方法模式(Template Method)
    父类定义算法骨架,子类实现具体步骤。
    应用:JdbcTemplate(封装 JDBC 固定流程,留自定义 SQL 执行逻辑)。
  • 观察者模式(Observer)
    定义一对多依赖,一个对象变化时通知所有依赖者。
    应用:Spring 事件机制(ApplicationEventListener)。
  • 迭代器模式(Iterator)
    提供遍历集合的统一接口,隐藏集合内部结构。
    应用:Java 集合的 Iterator 接口。
  • 责任链模式(Chain of Responsibility)
    多个对象处理请求,形成链条,每个对象决定是否处理或传递给下一个。
    应用:过滤器(Filter)链、日志级别处理(DEBUG→INFO→ERROR)。
  • 命令模式(Command)
    将请求封装为对象,使请求可参数化、队列化或撤销。
    应用:线程池的 Runnable(任务命令化)、遥控器按钮(每个按钮对应一个命令)。
  • 备忘录模式(Memento)
    保存对象状态,以便后续恢复。
    应用:编辑器的撤销功能(保存文本历史状态)。
  • 状态模式(State)
    对象状态变化时,动态改变其行为(将状态逻辑封装为不同类)。
    应用:订单状态流转(待支付→已支付→已发货→已完成)。
  • 访问者模式(Visitor)
    在不修改类的前提下,为类添加新操作(分离数据结构与操作)。
    应用:报表生成(同一组数据,生成不同格式报表)。
  • 中介者模式(Mediator)
    用中介者对象封装对象间的交互,减少直接依赖。
    应用:MVC 中的 Controller(中介者,协调 View 与 Model)。
  • 解释器模式(Interpreter)
    定义语言语法的解释器,用于解析特定格式的语句。
    应用:表达式解析(如数学公式、SQL 解析器)。

三、设计原则与模式的关系

  • 设计原则是 “道”,指导设计的方向(如高内聚、低耦合);设计模式是 “术”,是原则的具体实现方案。
  • 例如:
    • 开放 - 封闭原则 → 策略模式、装饰器模式;
    • 依赖倒置原则 → 工厂模式、抽象工厂模式;
    • 迪米特法则 → 外观模式、中介者模式。

四、常用的设计模式

1、单例模式

①懒汉式: 用的时候new对象,

package com.ape.danli.lanhanshi;

public class Student3 {
    //懒汉式,用的时候new 不用不new
    private String name;
    private static Student3 stu;
    public static synchronized Student3 getInstance(){
        if(stu==null){
            stu=new Student3();

        }
        return stu;
    }
}

②饿汉式: 一开始就new好,直接使用

package com.ape.danli.ehanshi;

public class Student2 {
    //饿汉式,直接new
    private static final Student2 stu=new Student2();
    public static synchronized Student2 getInstance(){
        return stu;
    }
}

2、工厂模式

  • 创捷接口或者父类(通过父子类或者接口实现)
package com.ape.duoli;

public interface Nooodle {
    public void noodleType();
}
  • 创建实现类实现接口中的方法(三种面条 youpo regan lanzhounurou)
package com.ape.duoli;

public class ReGan implements Nooodle{
    public void noodleType() {
        System.out.println("=======热干面========");
    }
}
package com.ape.duoli;

public class YouPo implements Nooodle{
    @Override
    public void noodleType() {
        System.out.println("=======油泼面========");
    }
}

package com.ape.duoli;

public class LanZhouNuRou implements Nooodle{
    public void noodleType() {
        System.out.println("=======兰州牛肉面========");
    }
}

  • 创建工厂类(面条工厂),生产不同的实现类对象(生产不同种类的面条)
package com.ape.duoli;

import sun.dc.pr.PRError;

public class NoodlesFactory {
    // 定义静态常量标记类型
    public static final int REGAN_TYPE = 1;
    public static final int YOUPO_TYPE = 2;
    public static final int LANZHOUNUROU_TYPE = 3;

    //生产面条对象
    public static Nooodle NoodleType(int type) {
        if (type == 1) {
            return new ReGan();
        }
        if (type == 2) {
            return new YouPo();
        }
        if (type == 3) {
            return new LanZhouNuRou();
        }
        return null;
    }
}
  • 测试类:
package com.ape.duoli;

import static com.ape.duoli.NoodlesFactory.LANZHOUNUROU_TYPE;
import static com.ape.duoli.NoodlesFactory.YOUPO_TYPE;


public class Test {
    public static void main(String[] args) {
        NoodlesFactory.NoodleType(1).noodleType();
        NoodlesFactory.NoodleType(YOUPO_TYPE).noodleType();
        Nooodle nooodle = NoodlesFactory.NoodleType(LANZHOUNUROU_TYPE);
        nooodle.noodleType();
    }
}

3、模板模式

父类定义算法骨架,子类实现具体步骤。
应用:JdbcTemplate(封装 JDBC 固定流程,留自定义 SQL 执行逻辑)

  • 创建父类
package com.ape.moban;

public abstract class Father {
    public final void 人生(){
        学习();
        工作();
        爱情();
    }
    public void 学习(){
        System.out.println("父亲: 需要学习");
    }
    public void 工作(){
        System.out.println("父: 需要工作");
    }
    public abstract void  爱情();
}
  • 创建子类,子类通过重写或者调用父类被final修饰的方法
package com.ape.moban;

public class Son extends Father {
    @Override
    public void 爱情() {
        System.out.println("子:撒浪嘿呦");
    }
    public void 学习() {
        System.out.println("子:好好学习天天向上");
    }
}

4、代理模式

1、含义:

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,通俗的来讲代理模式就是我们生活中常见的中介。

2、作用
  • 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
  • 增强方法(开闭原则,增加功能): 代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代,理类而不需要再修改委托类,符合代码设计的开闭原则。
3、代理模式
1、静态代理
  • 静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了。

案例:

  • 创建接口 代理对象与被代理对象同属于一个接口或一个父类
package com.ape.daili.staticdaili;

public interface IWoman {
    public void makeEyesWithMan();
}
  • 创建实现类潘金莲(被代理对象)
public class PanJingLian implements IWoman{
    @Override
    public void makeEyesWithMan() {
        System.out.println("===========回眸一笑百媚生============");
    }
}
  • 创捷王婆类(代理对象)
public class WangPo implements IWoman {
    private IWoman woman;

    public WangPo(IWoman woman) {
        this.woman = woman;
    }

    @Override
    public void makeEyesWithMan() {
        System.out.println("王婆:我给你找潘金莲!");
        woman.makeEyesWithMan();
    }
}
  • 创建西门庆测试类
public class XiMenQing {
    public static void main(String[] args) {
        PanJingLian panJingLian = new PanJingLian();
        WangPo wangPo = new WangPo(panJingLian);
        wangPo.makeEyesWithMan();
    }
}
2、动态代理(动态代理是在程序运行时通过反射机制动态创建的。)
  • 创建接口类型
public interface ISinger {
    public void sing();
    public void eat();
}
  • 基于接口的动态代理(jdk自带)
package com.ape.daili.dongtaidaili;

public class CaiXuKun implements ISinger{
    @Override
    public void sing() {
        System.out.println("==========鸡你太美=============");
    }
    public void eat(){
        System.out.println("鸡你太美,我要吃鸡");
    }
}
package com.ape.daili.dongtaidaili;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理====》jdk自带Proxy
 * */
/**
 * 基于接口的动态代理:
 *  特点:字节码随用随创建,随用随加载
 *  作用:不修改源码的基础上对方法增强
 *  涉及的类:Proxy
 *  提供者:JDK官方
 *  如何创建代理对象:
 *      使用Proxy类中的newProxyInstance方法
 *  创建代理对象的要求:
 *      被代理类最少实现一个接口,如果没有则不能使用
 *  newProxyInstance方法的参数:
 *      ClassLoader:类加载器
 *          它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
 *      Class[]:字节码数组
 *          它是用于让代理对象和被代理对象有相同方法。固定写法。
 *      InvocationHandler:用于提供增强的代码
 *
 */

public class Test {
    public static void main(String[] args) {
        CaiXuKun kun = new CaiXuKun();
        ISinger JInjiren=(ISinger) Proxy.newProxyInstance(kun.getClass().getClassLoader(), kun.getClass().getInterfaces(), new InvocationHandler() {
            /***
             *  Object proxy=====》被代理对象的引用===(蔡徐坤对象)
             *  Method method====》执行的方法========(蔡徐坤唱歌方法)
             *  Object[] args====》执行方法的参数=====(蔡徐坤唱歌方法的参数)
             *  Object===========》执行方法的返回值===(蔡徐坤唱歌方法的返回值)
             * */
            /**
             * 作用:执行被代理对象的任何接口方法都会经过该方法
             * 方法参数的含义
             *  proxy   代理对象的引用
             *  method  当前执行的方法
             *  args    当前执行方法所需的参数
             *  Object  和被代理对象方法有相同的返回值
             */

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if(method.getName().equals("sing")){
                    System.out.println("蔡徐坤正在唱歌");
                }
                System.out.println("我是蔡徐坤");
                Object obj = method.invoke(kun, args);
                return obj ;
            }
        });
        //接口中的方法
        JInjiren.sing();
        JInjiren.eat();

    }
}
  • 基于子类的动态代理(第三方)需要导入依赖(cglib)
public class ZhouShen implements ISinger{
    @Override
    public void sing() {
        System.out.println("周深在唱歌");
    }

    @Override
    public void eat() {
        System.out.println("周深在吃饭");
    }
}
package com.ape.daili.dongtaidaili;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

public class Test2 {
    //基于外部坏境的动态代理
    /**
     * 基于子类的动态代理
     *      涉及的类:Enhancer
     *      提供者:第三方cglib库
     *      开发环境:添加cglib依赖坐标
     *  如何创建代理对象:
     *      使用Enhancer类中的create方法
     *  创建代理对象的要求:
     *      被代理类不能是最终类
     *  create方法的参数:
     *      Class:字节码
     *          它是用于指定被代理对象的字节码。
     *
     *      Callback:用于提供增强的代码
     *          它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
     *          此接口的实现类都是谁用谁写。
     *          我们一般写的都是该接口的子接口实现类:MethodInterceptor
     *
     */

    public static void main(String[] args) {
        ZhouShen shen = new ZhouShen();
        /**
         * 2.创建代理对象
         * 参数1:被代理对象的字节码
         * 参数2:InvocationHandler
         * */
        /**
         * 执行北地阿里对象的任何方法都会经过该方法
         * @param proxy
         * @param method
         * @param args
         *    以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
         * @param methodProxy :当前执行方法的代理对象
         * @return
         * @throws Throwable
         */

        ISinger jPeople=(ISinger) Enhancer.create(shen.getClass(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("我是周深");
                Object object = method.invoke(shen, objects);
                if(method.getName().equals("sing")) {
                    System.out.println("代表作大鱼海棠");
                }
                return object;
            }
        });
        jPeople.sing();
        jPeople.eat();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呼哧呼哧.

栓Q!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值