大白话说Java设计模式-17-装饰器模式(源码剖析篇)

📌 PDF :AI人工智能 --- AI Agent智能体实战项目

大白话说Java设计模式-17-装饰器模式(源码剖析篇):JDK / Spring 中的装饰器实现

📌 一句话本质:装饰器在源码里不是"穿衣服"的形象化,而是"链式包装 + 同接口"的工业级架构。

🏷️ 标签:装饰器模式 / JDK IO / Collections 包装 / Spring BeanDefinitionDecorator 🎯 适合:中高级后端 / 想读懂主流框架源码的工程师


目录

  • 一、为什么读装饰器源码?一张地图先看清
  • [二、JDK 源码剖析:IO 装饰器家族](#二、JDK 源码剖析:IO 装饰器家族)
  • [三、JDK 源码剖析:Collections 装饰器](#三、JDK 源码剖析:Collections 装饰器)
  • [四、Spring 源码剖析:BeanDefinitionDecorator](#四、Spring 源码剖析:BeanDefinitionDecorator)
  • 五、为什么框架作者这么设计?
  • [六、借鉴到我们项目:3 个"抄作业"实践](#六、借鉴到我们项目:3 个"抄作业"实践)
  • [七、本篇小结 + 下一模式预告](#七、本篇小结 + 下一模式预告)

一、为什么读装饰器源码?一张地图先看清

装饰器模式在源码里出现得最经典 ------Java IO 流就是教科书级实现

源码地图

类别 框架 / 中间件 装饰器 用途
JDK java.io BufferedInputStream 缓冲
JDK java.io DataInputStream 按类型读
JDK java.io GZIPInputStream 解压
JDK java.io ObjectInputStream 对象序列化
JDK java.io PrintStream 格式化输出
JDK java.util Collections.synchronizedList 线程安全
JDK java.util Collections.unmodifiableList 不可变
JDK java.util Collections.checkedList 类型检查
Spring Spring Beans BeanDefinitionDecorator 装饰 Bean 定义
Spring Spring AOP IntroductionInfo 引入新接口
MyBatis MyBatis Cache 装饰器链 缓存装饰
Servlet Servlet API HttpServletRequestWrapper 包装请求

我们按"JDK IO → JDK Collections → Spring"的顺序来剖析。


二、JDK 源码剖析:IO 装饰器家族

2.1 FilterInputStream:装饰器基类

源码位置

  • OpenJDK 17
  • src/java.base/share/classes/java/io/FilterInputStream.java

核心源码

java 复制代码
/**
 * ✅ 装饰器基类:所有 IO 装饰器的父类
 */
public class FilterInputStream extends InputStream {

    /**
     * ✅ 持有被装饰者引用
     */
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    /**
     * 默认实现:调被装饰者的方法
     */
    @Override
    public int read() throws IOException {
        return in.read();
    }

    @Override
    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    @Override
    public long skip(long n) throws IOException {
        return in.skip(n);
    }

    @Override
    public int available() throws IOException {
        return in.available();
    }

    @Override
    public void close() throws IOException {
        in.close();
    }
}

关键点

角色
抽象组件 InputStream
装饰器基类 FilterInputStream
装饰器子类 BufferedInputStream / DataInputStream / ...

2.2 BufferedInputStream:缓冲装饰器

源码位置

  • OpenJDK 17
  • src/java.base/share/classes/java/io/BufferedInputStream.java

核心源码(简化版):

java 复制代码
/**
 * ✅ 装饰器:缓冲流
 * <p>
 * 默认 8192 字节缓冲区,提升 IO 性能
 */
public class BufferedInputStream extends FilterInputStream {

    /**
     * 缓冲区
     */
    protected volatile byte[] buf;

    /**
     * 缓冲区大小
     */
    protected int bufSize;  // 默认 8192

    public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);  // 8192
    }

    public BufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        this.bufSize = size;
        this.buf = new byte[size];
    }

    /**
     * ✅ 装饰器核心:填充缓冲区
     */
    private void fill() throws IOException {
        byte[] buffer = (buf == null) ? new byte[bufSize] : buf;
        int n = in.read(buffer, 0, bufSize);
        // ...
    }

    /**
     * ✅ 重写 read:先从缓冲区读
     */
    @Override
    public int read() throws IOException {
        // 先从缓冲区读
        if (pos >= count) {
            fill();  // 缓冲区空,从上游流读
        }
        return getBufIfOpen()[pos++] & 0xff;
    }

    @Override
    public int read(byte b[], int off, int len) throws IOException {
        // 优先从缓冲区读
        // 不够时再从上游流读
        // ...
    }
}

关键点

关键点 解释
extends FilterInputStream 继承装饰器基类
super(in) 持有被装饰者
重写 read() 加缓冲逻辑
不改变 InputStream 接口 装饰器核心

2.3 DataInputStream:类型装饰器

源码位置

  • OpenJDK 17
  • src/java.base/share/classes/java/io/DataInputStream.java

核心源码(简化版):

java 复制代码
/**
 * ✅ 装饰器:数据流(按类型读取)
 */
public class DataInputStream extends FilterInputStream implements DataInput {

    public DataInputStream(InputStream in) {
        super(in);
    }

    /**
     * 读取 boolean
     */
    public final boolean readBoolean() throws IOException {
        int ch = in.read();
        if (ch < 0) throw new EOFException();
        return (ch != 0);
    }

    /**
     * 读取 int
     */
    public final int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

    /**
     * 读取 UTF 字符串
     */
    public final String readUTF() throws IOException {
        // 读取 UTF-8 编码的字符串
        // ...
    }
}

关键点

关键点 解释
implements DataInput 加新接口(按类型读)
readBoolean() 装饰器加新方法
readInt() 装饰器加新方法
不破坏 InputStream 接口 仍能当 InputStream 用

2.4 GZIPInputStream:解压装饰器

源码位置

  • OpenJDK 17
  • src/java.base/share/classes/java/util/zip/GZIPInputStream.java

核心源码(简化版):

java 复制代码
/**
 * ✅ 装饰器:GZIP 解压流
 */
public class GZIPInputStream extends InflaterInputStream {

    public GZIPInputStream(InputStream in) throws IOException {
        super(in, new Inflater(), 512);
        // 读取 GZIP 头
        readHeader(in);
    }

    @Override
    public int read(byte[] buf, int off, int len) throws IOException {
        // 调父类(InflaterInputStream)的 read,自动解压
        return super.read(buf, off, len);
    }
}

/**
 * InflaterInputStream:通用解压流(装饰器)
 */
public class InflaterInputStream extends FilterInputStream {

    protected final Inflater inf;  // 解压器
    protected byte[] buf;          // 解压缓冲区

    public InflaterInputStream(InputStream in, Inflater inf, int size) {
        super(in);
        if (in == null || inf == null) throw new NullPointerException();
        this.inf = inf;
        this.buf = new byte[size];
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        // 调上游读 + 解压
        // ...
    }
}

关键点

关键点 解释
extends InflaterInputStream 继承通用解压装饰器
super(in, new Inflater(), 512) 持有上游 + 初始化解压器
重写 read 加 GZIP 头解析

2.5 完整 IO 装饰器链

java 复制代码
/**
 * ✅ 真实使用:链式装饰
 */
InputStream fileIn = new FileInputStream("data.txt");
InputStream bufferedIn = new BufferedInputStream(fileIn);  // 缓冲
DataInputStream dataIn = new DataInputStream(bufferedIn);   // 类型
InputStream gzIn = new GZIPInputStream(dataIn);            // 解压
ObjectInputStream objIn = new ObjectInputStream(gzIn);      // 对象

// 装饰链:
// ObjectInputStream → GZIPInputStream → DataInputStream → BufferedInputStream → FileInputStream

装饰链结构

复制代码
ObjectInputStream(对象流)
  ↓ in = GZIPInputStream
GZIPInputStream(解压流)
  ↓ in = DataInputStream
DataInputStream(数据流)
  ↓ in = BufferedInputStream
BufferedInputStream(缓冲流)
  ↓ in = FileInputStream
FileInputStream(文件流)

2.6 装饰器为什么设计得好?

关键点

特性 解释
同接口 所有流继承 InputStream
持有引用 protected InputStream in
链式调用 in.read() 层层向上
可嵌套 任意组合
可扩展 继承 FilterInputStream 加新装饰器

三、JDK 源码剖析:Collections 装饰器

3.1 Collections.synchronizedList:线程安全装饰器

源码位置

  • OpenJDK 17
  • src/java.base/share/classes/java/util/Collections.java

核心源码(简化版):

java 复制代码
/**
 * ✅ 装饰器:synchronized 集合
 */
public static <T> List<T> synchronizedList(List<T> list) {
    return (list instanceof RandomAccess ?
            new SynchronizedRandomAccessList<>(list) :
            new SynchronizedList<>(list));
}

/**
 * SynchronizedList 内部类
 */
static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {

    static final long serialVersionUID = -7754090372962971524L;

    final List<E> list;

    SynchronizedList(List<E> list) {
        super(list);
        this.list = list;
    }

    SynchronizedList(List<E> list, Object mutex) {
        super(list, mutex);
        this.list = list;
    }

    /**
     * ✅ 装饰器核心:所有方法加 synchronized
     */
    @Override
    public E get(int index) {
        synchronized (mutex) {
            return list.get(index);
        }
    }

    @Override
    public E set(int index, E element) {
        synchronized (mutex) {
            return list.set(index, element);
        }
    }

    @Override
    public void add(int index, E element) {
        synchronized (mutex) {
            list.add(index, element);
        }
    }

    @Override
    public E remove(int index) {
        synchronized (mutex) {
            return list.remove(index);
        }
    }

    @Override
    public int size() {
        synchronized (mutex) {
            return list.size();
        }
    }
}

关键点

关键点 解释
extends SynchronizedCollection 继承同步集合基类
super(list) 持有被装饰者
每个方法加 synchronized 装饰器加的逻辑
mutex 同步控制

完整装饰链

java 复制代码
List<String> list = new ArrayList<>();           // 节点
list = Collections.synchronizedList(list);       // 装饰 1:线程安全
// list = Collections.unmodifiableList(list);    // 装饰 2:不可变

// 调用 list.add("a") 会加锁
// 调用 list.get(0) 会加锁

3.2 Collections.unmodifiableList:不可变装饰器

核心源码(简化版):

java 复制代码
/**
 * ✅ 装饰器:不可变集合
 */
public static <T> List<T> unmodifiableList(List<? extends T> list) {
    return (list instanceof RandomAccess ?
            new UnmodifiableRandomAccessList<>(list) :
            new UnmodifiableList<>(list));
}

/**
 * UnmodifiableList 内部类
 */
static class UnmodifiableList<E> extends UnmodifiableCollection<E> implements List<E> {

    static final long serialVersionUID = -2546718832117073025L;

    final List<? extends E> list;

    UnmodifiableList(List<? extends E> list) {
        super(list);
        this.list = list;
    }

    /**
     * ✅ 装饰器核心:所有修改方法抛异常
     */
    @Override
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    @Override
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }

    @Override
    public E get(int index) {
        return list.get(index);  // 读操作不抛
    }
}

关键点

关键点 解释
所有修改方法抛异常 装饰器加的逻辑
读方法透传 不破坏读操作
返回的 List 接口相同 同接口

3.3 Collections.checkedList:类型检查装饰器

核心源码(简化版):

java 复制代码
/**
 * ✅ 装饰器:类型检查集合
 */
public static <E> List<E> checkedList(List<E> list, Class<E> type) {
    return (list instanceof RandomAccess ?
            new CheckedRandomAccessList<>(list, type) :
            new CheckedList<>(list, type));
}

/**
 * CheckedList 内部类
 */
static class CheckedList<E> extends CheckedCollection<E> implements List<E> {

    final List<E> list;

    CheckedList(List<E> list, Class<E> type) {
        super(list, type);
        this.list = list;
    }

    /**
     * ✅ 装饰器核心:插入时检查类型
     */
    @Override
    public void add(int index, E element) {
        typeCheck(element);  // ✅ 类型检查
        list.add(index, element);
    }

    @Override
    public E set(int index, E element) {
        typeCheck(element);
        return list.set(index, element);
    }

    void typeCheck(Object o) {
        if (o != null && !type.isInstance(o)) {
            throw new ClassCastException(badElementMsg(o));
        }
    }
}

关键点

关键点 解释
插入时类型检查 装饰器加的逻辑
typeCheck 核心方法
防类型污染 应对 Java 泛型擦除

3.4 Collections 装饰器对比表

装饰器 加的功能 装饰方法
synchronizedList 线程安全 synchronized
unmodifiableList 不可变 抛异常
checkedList 类型检查 typeCheck
unmodifiableSortedSet 不可变 + 排序 抛异常 + 保持顺序

业务启示

Collections 装饰器是"Java 标准装饰器模式" 。需要线程安全?包一层 synchronizedList。需要不可变?包一层 unmodifiableList任意组合,互不干扰


四、Spring 源码剖析:BeanDefinitionDecorator

4.1 BeanDefinitionDecorator 接口

源码位置

  • Spring Framework 6.1.x
  • spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionDecorator.java

核心源码

java 复制代码
/**
 * ✅ Spring 装饰器:装饰 Bean 定义
 */
public interface BeanDefinitionDecorator {

    /**
     * 装饰 BeanDefinition
     */
    BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext);
}

关键点

角色
抽象组件 BeanDefinitionHolder
装饰器 BeanDefinitionDecorator(接口)
具体装饰器 DefaultBeanDefinitionDecorator

4.2 DefaultBeanDefinitionDecorator:默认装饰器

源码位置

  • spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDecorator.java

核心源码(简化版):

java 复制代码
/**
 * ✅ Spring 默认 BeanDefinition 装饰器
 */
public class DefaultBeanDefinitionDecorator implements BeanDefinitionDecorator {

    private static final String ATTRIBUTE_EQUAL = "=";
    private static final String ATTRIBUTE_PROPERTY = "property";

    @Override
    public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
        // 1️⃣ 解析属性
        // 2️⃣ 应用到 BeanDefinition
        // 3️⃣ 返回装饰后的 BeanDefinition

        // 例如 <bean id="user" class="User" p:age="20"/>
        // 这里会解析 p:age 属性,设置到 BeanDefinition

        return definition;
    }
}

关键点

关键点 解释
装饰 Bean 定义 在 Bean 创建前装饰
不影响 Bean 类 只改 BeanDefinition
自定义装饰器 实现 BeanDefinitionDecorator 接口

4.3 Spring 用装饰器模式的 3 个场景

场景 装饰器 作用
Bean 属性装饰 DefaultBeanDefinitionDecorator 解析 p: 属性
事务装饰 @Transactional 加事务拦截器
缓存装饰 @Cacheable 加缓存拦截器

@Transactional 的本质是装饰器

java 复制代码
/**
 * Spring 事务 = 装饰器模式
 */
@Service
public class OrderService {

    @Transactional  // ✅ 装饰:加事务
    public void createOrder() {
        // 业务代码
    }
}

完整装饰链

复制代码
OrderService(业务)
  ↓ 装饰
TransactionInterceptor(事务)
  ↓ 装饰
LogAspect(日志)
  ↓ 装饰
最终代理对象

五、为什么框架作者这么设计?

读源码看的是"实现",悟的是"设计哲学"。

5.1 框架作者选装饰器的 4 个核心考虑

序号 考虑 举例
动态叠加功能 Java IO 流
同接口不破坏 Collections 装饰器
可任意组合 Buffered + Data + GZIP + Object
加新功能不改老 加新装饰器不动原有

5.2 装饰器 vs 继承:JDK 的选择

Java IO 早期有人提过用继承扩展,但:

  • BufferedFileInputStream extends FileInputStream
  • DataFileInputStream extends FileInputStream
  • GZIPFileInputStream extends FileInputStream
  • 组合起来:BufferedDataGZIPFileInputStream extends ???

类数量爆炸,无法维护

改用装饰器

  • BufferedInputStream 装饰 FileInputStream
  • DataInputStream 装饰 BufferedInputStream
  • GZIPInputStream 装饰 DataInputStream
  • 任意组合,类数量恒定

5.3 框架作者不选装饰器的 3 种情况

序号 场景 原因
只加一个功能 装饰器是多余的
功能影响接口 用继承
顺序固定 用普通方法

5.4 装饰器在企业级应用的 3 种典型用法

复制代码
用法 1:数据流加工
       JSON → 压缩 → 加密 → Base64
       → 任意组合

用法 2:报表导出
       Excel → 加图表 → 加边框 → 加水印
       → 任意组合

用法 3:权限校验链
       登录 → 角色校验 → 资源权限校验
       → 任一失败即拒绝

六、借鉴到我们项目:3 个"抄作业"实践

6.1 实践 1:数据导出流

场景:大白商城的数据导出支持 JSON / Excel / 压缩 / 加密任意组合。

完整实现

java 复制代码
/**
 * 借鉴 Java IO:数据导出装饰器
 */
public abstract class DataExporter {

    public abstract byte[] export(Object data);
}

/**
 * 节点导出器:JSON
 */
public class JsonExporter extends DataExporter {

    @Override
    public byte[] export(Object data) {
        return JSON.toJSONBytes(data);
    }
}

/**
 * 装饰器:压缩
 */
public class CompressExporter extends DataExporter {

    private final DataExporter wrapped;

    public CompressExporter(DataExporter wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public byte[] export(Object data) {
        byte[] raw = wrapped.export(data);
        // GZIP 压缩
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
            gzos.write(raw);
        } catch (IOException e) {
            throw new RuntimeException("压缩失败", e);
        }
        return baos.toByteArray();
    }
}

/**
 * 装饰器:加密
 */
public class EncryptExporter extends DataExporter {

    private final DataExporter wrapped;
    private final String key;

    public EncryptExporter(DataExporter wrapped, String key) {
        this.wrapped = wrapped;
        this.key = key;
    }

    @Override
    public byte[] export(Object data) {
        byte[] raw = wrapped.export(data);
        // AES 加密
        // ...
        return encrypted;
    }
}

// 使用:JSON → 压缩 → 加密
DataExporter exporter = new JsonExporter();
exporter = new CompressExporter(exporter);
exporter = new EncryptExporter(exporter, "secret_key");
byte[] result = exporter.export(data);

收益

优化点 效果
任意组合 JSON 可加可不加密,可选压缩
加新格式 加新 Exporter,链不动
代码简洁 没有 if-else

6.2 实践 2:商品 VO 装饰器

场景:商品详情 VO 包含基础信息 + 标签 + 图片 + 规格,可按需叠加。

完整实现

java 复制代码
/**
 * 借鉴 Collections 装饰器:商品 VO 装饰器
 */
public abstract class GoodsVoDecorator implements GoodsVoSupplier {

    protected final GoodsVoSupplier wrapped;

    public GoodsVoDecorator(GoodsVoSupplier wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public GoodsVo get() {
        return wrapped.get();
    }
}

/**
 * 装饰器:加标签
 */
public class WithTagsDecorator extends GoodsVoDecorator {

    public WithTagsDecorator(GoodsVoSupplier wrapped) {
        super(wrapped);
    }

    @Override
    public GoodsVo get() {
        GoodsVo vo = super.get();
        vo.setTags(List.of("热销", "新品", "包邮"));
        return vo;
    }
}

/**
 * 装饰器:加图片
 */
public class WithImagesDecorator extends GoodsVoDecorator {

    public WithImagesDecorator(GoodsVoSupplier wrapped) {
        super(wrapped);
    }

    @Override
    public GoodsVo get() {
        GoodsVo vo = super.get();
        vo.setImages(List.of("img1.jpg", "img2.jpg"));
        return vo;
    }
}

// 使用:基础 VO + 标签 + 图片
GoodsVoSupplier supplier = new BaseGoodsVo();
supplier = new WithTagsDecorator(supplier);
supplier = new WithImagesDecorator(supplier);
GoodsVo vo = supplier.get();

6.3 实践 3:日志装饰器

场景:日志支持控制台输出 / 文件输出 / 远程上报,任意组合。

完整实现

java 复制代码
/**
 * 借鉴 Java IO 装饰器:日志装饰器
 */
public abstract class Logger {

    public abstract void log(String message);
}

/**
 * 节点:内存日志
 */
public class MemoryLogger extends Logger {

    private final List<String> logs = new ArrayList<>();

    @Override
    public void log(String message) {
        logs.add(message);
    }
}

/**
 * 装饰器:控制台输出
 */
public class ConsoleLogger extends Logger {

    private final Logger wrapped;

    public ConsoleLogger(Logger wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public void log(String message) {
        wrapped.log(message);
        System.out.println("[CONSOLE] " + message);
    }
}

/**
 * 装饰器:文件输出
 */
public class FileLogger extends Logger {

    private final Logger wrapped;
    private final String filePath;

    public FileLogger(Logger wrapped, String filePath) {
        this.wrapped = wrapped;
        this.filePath = filePath;
    }

    @Override
    public void log(String message) {
        wrapped.log(message);
        // 写入文件
        // Files.write(Paths.get(filePath), message.getBytes(), StandardOpenOption.APPEND);
    }
}

// 使用:内存 + 控制台 + 文件
Logger logger = new MemoryLogger();
logger = new ConsoleLogger(logger);
logger = new FileLogger(logger, "/var/log/app.log");
logger.log("Hello World");
// 输出:内存 + 控制台 + 文件 三个地方都有

收益

优化点 效果
任意组合 内存/控制台/文件可选
加新输出 加新 Logger 装饰器
配置化 运行时选择装饰链

七、本篇小结 + 下一模式预告

7.1 本篇小结(5 个核心要点)

  1. JDK IO 装饰器FilterInputStream 装饰器基类,BufferedInputStream / DataInputStream / GZIPInputStream 叠加功能,教科书级实现
  2. Collections 装饰器synchronizedList / unmodifiableList / checkedList任意组合
  3. Spring 装饰器@Transactional 本质是装饰器,事务 = 装饰器模式
  4. 设计哲学同接口 + 持有引用 + 链式调用 + 可嵌套
  5. 借鉴价值 :数据导出 / 商品 VO / 日志,任意叠加用装饰器

7.2 一句话总结

装饰器在源码里不是"穿衣服"的形象化,而是"链式包装 + 同接口"的工业级架构 。Java IO 流是教科书,Collections 装饰器是另一经典,Spring 事务本质也是装饰器。学装饰器,先学 Java IO

7.3 知识脑图

复制代码
装饰器源码剖析
├── JDK IO
│   ├── FilterInputStream(基类)
│   ├── BufferedInputStream(缓冲)
│   ├── DataInputStream(类型)
│   ├── GZIPInputStream(解压)
│   └── ObjectInputStream(对象)
├── JDK Collections
│   ├── synchronizedList(线程安全)
│   ├── unmodifiableList(不可变)
│   └── checkedList(类型检查)
├── Spring
│   ├── BeanDefinitionDecorator(Bean 装饰)
│   └── @Transactional(事务装饰)
└── 借鉴价值
    ├── 数据导出流
    ├── 商品 VO 装饰器
    └── 日志装饰器

7.4 下一模式预告

第 18 篇【外观模式 - 业务实战篇】:大白商城下单门面的"一站式服务"

下一篇我们会实战外观模式,回答 4 个问题:

  1. 大白商城下单为什么要"一站式服务"?
  2. 外观 vs 适配器 / 中介者怎么区分?
  3. SLF4J 的 LoggerFactory 怎么借鉴外观?
  4. Spring 的 JdbcTemplate 怎么借鉴外观?

并附完整的下单门面实战代码(含订单/库存/支付/物流 4 个子系统 + 外观 + 单元测试),可直接复制到 IDEA 跑


觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯

相关推荐
艺艺生辉1 小时前
从if-else到策略模式
后端·设计模式
小林ixn2 小时前
单例模式:从弹窗管理到全局状态,一个模式搞定
前端·javascript·设计模式
桦说编程2 小时前
盘点并发集合里那些容易误判的行为
java·后端·性能优化
IT爱学堂3 小时前
java版数据结构和算法+AI算法和技能学习指南
java·开发语言
lv__pf3 小时前
spring之整合mybatis【TL spring 12】
mysql·spring·mybatis
evans在进步3 小时前
LeetCode 394:字符串解码——Java 单栈模拟与嵌套解析详解
java·python·leetcode
m0_547486664 小时前
《Java程序设计与实践 》全套PPT课件2026
java·开发语言
土司大王4 小时前
LeetCode hto100——字母异位词分组
java·算法·leetcode
码匠许师傅5 小时前
【C++ 面试真题】聊聊 C++ 中的 lambda 表达式
java·c++·面试