戴老师的博客 - 设计模式
type: channel
link: https://tushu.info/tag/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/
items: Java源码分析：深入探讨Iterator模式——迭代器模式
items: Java设计模式概述
items: Java设计模式——装饰模式与代理模式：深度剖析差异与应用
items: Java-23种设计模式
items: Java 设计模式——观察者模式：从优衣库不使用新疆棉事件看系统的动态响应
items: Java设计模式——装饰器(Decorator.html)模式
items: 羽绒服割不动年轻人？Java代码教你“穿”出新选择！
items: Tomcat 系统架构与设计模式
items: Java设计模式——享元模式
items: Java设计模式——策略、代理模式

Java源码分析：深入探讨Iterator模式——迭代器模式
type: item
date: 2026-07-09T04:39:44+00:00
description: 引言java.util 包中包含了一系列重要的集合类。本文将从源码分析入手，深入研究集合类的内部结构，以及遍历集合的迭代器模式（Iterator Pattern）的源码实现内幕。我们将先讨论根接口 Collection，然后分析抽象类 AbstractList 及其对应的 Iterator 接口，仔细研究迭代器模式的实现原理。说明：本文讨论的源代码版本基于 JDK 1.4.2。JDK 1.5 及后续版本在 java.util 中引入了泛型（Generics），为了简化问题并聚焦核心原理，本文主要讨论 1.4 版本的代码逻辑，但核心设计思想在后续版本中依然适用。集合类的根接口 CollectionCollection 接口是所有集合类的根类型。它的一个主要接口方法如下：boolean add(Object o.html)add() 方法用于添加一个新元素。注意该方法返回一个 boolean 值，但返回值不是表示添加成功与否。仔细阅读文档可以看到，Collection 规定：如果一个集合拒绝添加这个元素（无论任何原因），都必须抛出异常。返回值表示的意义是：add() 方法执行后，集合的内容是否改变了（即元素有无数量、位置等变化），具体行为由实现类决定。即：如果方法出错，总会抛出异常；返回值仅仅表示该方法执行后这个 Collection 的内容有无变化。类似的方法还有：boolean addAll(Collection c.html); boolean remove(Object o.html); boolean removeAll(Collection c.html); boolean retainAll(Collection c.html);Object[] toArray() 方法很简单，把集合转换成数组返回。Object[] toArray(Object[] a.html) 方法则稍微复杂一些：返回的 Object[] 仍然是把集合的所有元素变成的数组，但是类型和参数 a 的类型是相同的。例如执行：String[] o = (String[].html)c.toArray(new String[0].html);得到的 o 实际类型是 String[]。如果参数 a 的大小装不下集合的所有元素，返回的将是一个新的数组。如果参数 a 的大小能装下集合的所有元素，则返回的还是 a，但 a 的内容用集合的元素来填充。尤其要注意的是，如果 a 的大小比集合元素的个数还多，a 后面的部分全部被置为 null。最后一个最重要的方法是 iterator()，返回一个 Iterator（迭代器），用于遍历集合的所有元素。使用 Iterator 模式遍历集合Iterator 模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来，从而避免向客户端暴露集合的内部结构。例如，如果没有使用 Iterator，遍历一个数组的方法是使用索引：for(int i = 0; i < array.size(.html); i++) { // TODO: get(i.html) ... }而访问一个链表（LinkedList）又必须使用 while 循环：while((e = e.next(.html)) != null) { // TODO: e.data() ... }以上两种方法客户端都必须事先知道集合的内部结构，访问代码和集合本身是紧耦合，无法将访问逻辑从集合类和客户端代码中分离出来。每一种集合对应一种遍历方法，客户端代码无法复用。更严重的是，如果以后需要把 ArrayList 更换为 LinkedList，则原来的客户端代码必须全部重写。为解决以上问题，Iterator 模式总是用同一种逻辑来遍历集合：for(Iterator it = c.iterator(.html); it.hasNext(); ) { // ... }奥秘在于客户端自身不维护遍历集合的“指针”，所有的内部状态（如当前元素位置，是否有下一个元素）都由 Iterator 来维护。而这个 Iterator 由集合类通过工厂方法生成，因此，它知道如何遍历整个集合。客户端从不直接和集合类打交道，它总是控制 Iterator，向它发送“向前”、“向后”、“取当前元素”的命令，就可以间接遍历整个集合。首先看看 java.util.Iterator 接口的定义：public interface Iterator { boolean hasNext(); Object next(); void remove(); }依赖前两个方法就能完成遍历，典型的代码如下：for(Iterator it = c.iterator(.html); it.hasNext(); ) { …

Java设计模式概述
type: item
date: 2026-07-09T04:39:11+00:00
description: Java 设计模式概述设计模式的重要性在软件开发领域，变化是永恒的主题。从项目启动到后期维护，需求变更、技术演进以及环境变化无处不在。我们面临的关键挑战，是如何以最小的成本和最大的灵活性来适应这些变化。幸运的是，前人在应对各种设计问题时积累了丰富的经验，并形成了被广泛认可的最佳实践，这就是“设计模式”（Design Patterns）。设计模式提供了经过验证的解决方案，能够帮助我们构建更优质、更具扩展性的软件系统。接下来，我们将深入探讨两种经典的设计模式：适配器模式和单例模式。适配器模式（Adapter Pattern）1. 应用场景假设存在一个旧系统，原本使用特定接口与系统其他部分交互。当需要引入一个新的第三方库时，问题出现了：新库采用了完全不同的 API，与旧系统适用的接口不兼容。此时，直接修改旧系统的代码以适应新接口是一种高风险且不推荐的做法，尤其是对于大型复杂的旧系统，可能会引发一系列难以预料的问题。适配器模式提供了一种优雅的解决方案：它允许我们创建一个适配器（新的封装类），使不兼容的类能够协同工作。2. 核心原理适配器模式利用接口，将不兼容的接口进行转换，使其能够被客户端正确解析。通过这种方式，它在不兼容的类之间架起了一座桥梁，实现了不同接口之间的通信，而无需修改原有客户端代码。3. 代码实战旧系统接口与客户端代码旧系统使用 LegacyVideoController 接口来控制视频系统：public interface LegacyVideoController { /** * Begins the playback after startTimeTicks * from the beginning of the video * @param startTimeTicks time in milliseconds */ public void startPlayback(long startTimeTicks.html); // 其他可能的方法... }客户端使用该控制器的方式如下：public void playBackVideo(long timeToStart, LegacyVideoController controller.html) { if (controller != null.html) { controller.startPlayback(timeToStart.html); } }用户需求变更与新接口随着业务发展，新的视频控制器接口 AdvancedVideoController 被引入：public interface AdvancedVideoController { /** * Places the controller head after time * from the beginning of the track * @param time time defines how much seek is required */ public void seek(Time time.html); /** * Plays the track */ public void play(); }这导致原有的客户端代码失效，因为新接口与旧接口不兼容。适配器类的实现为解决接口不兼容问题，我们创建一个适配器类 AdvancedVideoControllerAdapter：public class AdvancedVideoControllerAdapter implements LegacyVideoController { private AdvancedVideoController advancedVideoController; public AdvancedVideoControllerAdapter(AdvancedVideoController advancedVideoController.html) { this.advancedVideoController = advancedVideoController; } @Override public void startPlayback(long startTimeTicks.html) { // 将 long 类型转换为 Time 类型（假设存在相应转换方法） Time startTime = getTime(startTimeTicks.html); // 适配操作 advancedVideoController.seek(startTime.html); advancedVideoController.play(); } }适配器实现了目标接口 LegacyVideoController，这样无需更改客户端代码。适配器类持有需…

Java设计模式——装饰模式与代理模式：深度剖析差异与应用
type: item
date: 2026-07-09T04:38:31+00:00
description: 初始困惑：相似表象下的疑问在设计模式的探索旅程中，开发者经常会遇到一些容易混淆的概念。装饰模式（Decorator Pattern）与代理模式（Proxy Pattern）便是其中典型的一对。乍看之下，二者结构相似，均涉及对原始对象的包装，但实际上它们在设计意图与应用场景上有着本质的区别。本文将深入剖析这两种模式，明确它们的差异，并探讨如何在实际开发中正确运用。表面功能的混淆从结构上看，这两种模式都允许在原始对象的方法调用前后添加额外操作。它们都能在不修改原始对象代码的前提下，为其增加新的功能或控制逻辑。这种“非侵入式”的增强能力，是导致两者容易被混淆的主要原因。然而，若深入探究其背后的设计思想，便会发现它们如同两座看似相近的山峰，实则拥有不同的地貌与生态。本质区别：核心设计理念大揭秘装饰模式：动态扩展功能的利器装饰模式的核心关注点在于为对象动态地添加新的功能。它类似于一个灵活的“工具箱”，开发者可以根据需要随时组合不同的装饰者来增强对象的能力。例如，假设有一个基础手机对象，通过装饰模式，可以为其添加手机壳（保护功能）、耳机（音频增强功能）等配件。每添加一个配件，对象的功能便变得更加丰富，且这些配件可以自由组合，具有极高的灵活性。下面是一个简单的 Java 代码示例，展示了装饰模式的实现：// 定义一个接口 interface Shape { void draw(); } // 具体的被装饰对象：圆形 class Circle implements Shape { @Override public void draw() { System.out.println("绘制一个圆形".html); } } // 抽象装饰者类 abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape.html) { this.decoratedShape = decoratedShape; } @Override public void draw() { decoratedShape.draw(); } } // 具体装饰者类：给形状添加颜色 class ColoredShapeDecorator extends ShapeDecorator { private String color; public ColoredShapeDecorator(Shape decoratedShape, String color.html) { super(decoratedShape.html); this.color = color; } @Override public void draw() { super.draw(); System.out.println("用 " + color + " 颜色填充形状".html); } }在客户端代码中，我们可以这样使用装饰模式：public class Client { public static void main(String[] args.html) { Shape circle = new Circle(); // 动态添加颜色装饰 Shape coloredCircle = new ColoredShapeDecorator(circle, "红色".html); coloredCircle.draw(); } }代理模式：访问控制与资源管理的守护者代理模式则专注于控制对对象的访问以及管理对象的资源。它类似于一个严格的“管理员”，决定了谁能够访问对象，以及在什么情况下可以访问。代理类可以对客户端隐藏对象的内部细节，在对象周围设置一道安全屏障，只有经过授权的操作才能通过代理类传递到真实对象。例如，在网络访问中，代理服务器可以控制用户对特定网站的访问权限；在对象加载时，代理类可以先进行初始化操作（如延迟加载），然后再将请求转发给真实对象。以下是一个简单的代理模式 Java 代码示例（静态代理）：// 定义一个接口 interface Image { void display(); } // 真实的图像类 class RealImage implements Image { private String fileName; public RealImage(String fileName.html) { this.fileName = fileName; loadFromDisk(fileName.html); } private void loadFromDisk(String fileName.html) { Sys…

Java-23种设计模式
type: item
date: 2026-07-09T04:38:00+00:00
description: 一、设计模式的分类与设计原则设计模式总体分为三大类：创建型模式（5 种）、结构型模式（7 种）和行为模式（11 种）。在深入了解各种设计模式之前，先明确一下设计所遵循的原则，主要包括：单一职责原则：一个类应该只有一个引起它变化的原因。开放封闭原则（OCP）：功能开放，代码闭合。里氏替换原则：子类型能够替换掉父类型，实现松耦合。接口隔离原则（ISP）：不能出现胖接口，应该打散 DAO，多定义子接口。这些原则为设计模式的合理运用提供了指导方针，确保软件系统具备良好的可维护性、扩展性和灵活性。二、创建型模式1. 单例模式（Singleton）特征描述：构造函数必须声明为私有，防止外部直接实例化该类。类中声明静态常量，用于保存类的惟一实例。为客户提供一个静态的方法，该方法能够返回惟一实例。应用场景：当类只能有一个实例且客户可从一个众所周知的访问点访问它时。例如在一些全局配置类中，整个系统只需要一个配置实例来保证配置的一致性。当这个惟一实例应通过子类化可扩展，且客户无需更改代码就能使用扩展实例时。如在数据库连接池的实现中，单例模式可以确保在整个应用中只有一个连接池实例，同时可以根据不同的数据库类型进行子类扩展。伪单例模式：线程单例：保证在一个线程中只有一个实例。在 Java 中可通过 ThreadLocal 对象实现。在 Hibernate 中，Session 的使用就运用了线程单例，确保每个线程都有自己独立的 Session 实例，避免线程安全问题。在自定义应用中，对于那些没有实现线程安全但又必须保证线程安全的对象，可设置为线程单例。通过线程同步实现线程安全，这样做的好处是可以提高程序在多线程环境下的稳定性和可靠性。类加载器单例：保证在一个类加载器中只有一个类的实例。在 BeanUtils 中，与 Utils 相对应的 Bean 采用了类加载器单例。在自定义应用中，可将需要在应用间相互隔离但又必须使用单例的对象设置成类加载器单例，常用于隔离 WEB 应用程序之间的单例。其具体作法是使用一个 Map，键为类加载器引用，值存储对象。若能通过类加载器对象得到实例则不再创建，否则创建并存储。相对特定上下文单例：其他相对特定上下文的伪单例模式均可采用类似方法，确保在特定的上下文环境中只有一个实例存在，满足不同场景下对单例的需求。2. 原型模式（Prototype）特征描述：实现原型模式的类必须由统一的接口或类继承而来，并且实现接口或类中定义的 clone 方法。在 clone 方法中实现对象克隆，从而创建新的对象。应用场景：当要实例化的类在运行时刻指定时，例如通过动态装载，可利用原型模式快速创建对象。为避免创建与产品类层次平行的工厂类层次时，原型模式提供了一种简洁的对象创建方式。当一个类的实例只有几种不同状态组合中的一种时，建立相应数目的原型并克隆它们比每次用合适状态手工实例化该类更方便。比如在游戏开发中，不同状态的游戏角色可以通过原型模式快速创建。3. 工厂方法模式（Factory Method）特征描述：顶级类定义创建对象的抽象方法，将对象的创建延迟到子类。具体子类实现该方法，返回具体产品。可将工厂方法参数化，以满足不同的创建需求。应用场景：当一个类不知道它所必须创建的对象的类时，可使用工厂方法模式，让子类来决定创建何种对象。当一个类希望由它的子类来指定所创建的对象时。例如在一个图形绘制系统中，父类定义了绘制图形的方法，但具体绘制哪种图形（如圆形、矩形等）由子类决定。当类将创建对象的职责委托给多个帮助子类中的某一个，且希望将哪一个帮助子类是代理者这一信息局部化时，工厂方法模式可以很好地实现这种职责委托。典型案例：Collection 的 iterator 方法返回 Iterator 可认为是工厂方法的一种典型应用，它为遍历集合提供了统一的方式，不同类型的集合可以返回相应类型的迭代器。Hibernate 中，SessionFactory.openSession 是工厂方法模式的体现，根据不同的配置和需求创建合适的 Session 实例。Spring 中，BeanFactory.getBean 和 FactoryBean.getObject 也是工厂方法模式的应用，用于获取不同类型的 Bean 实例。4. 抽象工厂模式（Abstract Factory）特征描述：定义抽象工厂，用于声明创建一系列相关或相互依赖对象的接口。定义抽象产品系列，确定产品的类型和结构。一个具体工厂对应一个具体产品系列，通过实现抽象工厂的方法来创建所需的产品对象。可以使用工厂方法模式或原型模式实现（也可参数化工厂方法），并且通常工厂类应为单例模式，以保证整个系统中只有一个工厂实例来创建产品。存在的问题是无法在已有产品系中增加新的产品，这是其局限性所在。应用场景：当一个系统…

Java 设计模式——观察者模式：从优衣库不使用新疆棉事件看系统的动态响应
type: item
date: 2026-07-09T04:37:45+00:00
description: 背景与引言背景事件：近日，优衣库宣布不再使用新疆棉花，这一举措引发了广泛的社会讨论。消费者的反应和舆论的压力，让优衣库的决策迅速影响了市场和品牌形象。类似的，许多软件系统也面临着需要根据外部事件或状态的变化，做出即时反应的需求。在软件设计中，观察者模式（Observer Pattern） 正是为了处理这种“状态变化与反应”的需求而生。它允许一个对象（主题）在状态发生变化时，通知所有依赖它的对象（观察者），而不需要显式的调用，从而实现模块间的松耦合与动态更新。今天，我们将结合优衣库棉花事件这一业务场景，讲解如何使用观察者模式来应对复杂系统中的事件驱动响应。一、观察者模式概述1.1 观察者模式的定义观察者模式属于行为型设计模式（Behavioral Pattern）。其核心思想是：当对象的状态发生改变时，所有依赖于它的对象都会收到通知并自动更新。这种模式非常适用于系统中某一部分状态变化需要同时通知到其他部分的场景。1.2 观察者模式的组成部分主题（Subject）：状态变化的核心对象，负责管理所有的观察者并通知它们。观察者（Observer）：依赖于主题对象的变化，并作出响应。通知机制：通过注册和触发通知，观察者获得主题对象的状态变化。在优衣库不使用新疆棉的事件类比中，品牌决策就像主题对象，而消费者、舆论、媒体等就是观察者。每当品牌作出决策，消费者的情感、舆论的反应都会发生变化，观察者（消费者）的情绪或行为会随之改变。二、观察者模式与优衣库事件的类比2.1 事件背景假设优衣库公司决定不再使用新疆棉，这一决策会触发不同的消费者、股东、媒体等不同的观察者产生反应：消费者：可能对这一举措产生负面或正面的情绪，甚至会改变购买行为。媒体：可能会通过报道引导舆论。股东：可能对这一决策的影响做出反应，调整投资策略。这些变化是动态的，且每当优衣库做出决策时，所有相关的观察者（消费者、媒体等）都会收到通知并做出相应反应。2.2 在系统设计中的应用在类似的业务场景中，观察者模式非常有用。通过观察者模式，当主题（如优衣库品牌决策）发生变化时，所有需要响应变化的组件（如消费者、舆论）都会自动收到通知并执行相应的处理逻辑。这种设计使得不同的模块之间保持了松耦合的关系，不需要主题对象知道观察者的具体细节。三、观察者模式的实现接下来，我们通过代码来实现一个基于观察者模式的简单示例，模拟优衣库品牌决策引发的消费者反应。3.1 代码示例：实现观察者模式import java.util.ArrayList; import java.util.List; // 主题接口 interface BrandDecision { void addObserver(ConsumerObserver observer.html); void removeObserver(ConsumerObserver observer.html); void notifyObservers(); } // 具体主题：优衣库的品牌决策 class UniqloBrandDecision implements BrandDecision { private List<ConsumerObserver> observers = new ArrayList<>(); private String decision; @Override public void addObserver(ConsumerObserver observer.html) { observers.add(observer.html); } @Override public void removeObserver(ConsumerObserver observer.html) { observers.remove(observer.html); } @Override public void notifyObservers() { for (ConsumerObserver observer : observers.html) { observer.update(decision.html); } } public void makeDecision(String decision.html) { this.decision = decision; System.out.println("优衣库品牌做出决策：" + decision.html); notifyObservers(); } } // 观察者接口：消费者反应 interface ConsumerObserver { void update(String decision.html); } // 具体观察者：消费者 class Consumer implements C…

Java设计模式——装饰器(Decorator.html)模式
type: item
date: 2026-07-09T04:37:42+00:00
description: 1. 装饰器模式概述装饰器（Decorator）设计模式属于典型的结构型模式（在 GoF 的模式分类中，模式分为创建型、结构型、行为模式三种）。其核心目的在于动态地为对象添加额外功能，这也是理解装饰器模式的关键所在。正如 GoF 在《Elements of Reusable Object-Oriented Software》中所概述："Decorator Pattern――Attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality."2. 应用场景：何时使用装饰器模式在 GoF 的相关书籍中，常以文本组件与边框的例子阐述装饰器模式。这里我们以一个更具说服力的“三明治”例子来说明其必要性。假设要为三明治小店构建程序，设计各种三明治对象。若采用传统继承方式，从简单的 Sandwich 对象开始，若要创建带蔬菜的三明治就继承原有 Sandwich 并添加蔬菜成员变量；后续若要添加咸肉、奶油等多种成分，且考虑各种成分的任意组合，那么继承方式将导致类的数量急剧膨胀。例如，若有 n 种成分，根据组合数学知识，不同组合方案数为 2^n 种（即 $C_{n}^0 + C_{n}^1 + \cdots + C_{n}^n$）。这意味着每增加一种成分，工作量可能成倍增加，同时类库也会变得极为庞大。而装饰器模式则能有效解决此类问题，通过组合而非继承来扩展功能。3. 设计与实现3.1 类结构设计Ingredient（成分）所有类的父类，一般为抽象类且方法有默认实现，也可为接口。它包含所有成分共有的方法，如描述自身的 getDescription 方法、获取价格的 getCost 方法，以及打印自身描述和价格的 printDescription 方法（构成模板方法）。Bread（面包）三明治中必需的两片面包，是系统中最基本元素，也是被装饰的元素，类似 IO 中的媒质流（原始流）。它是具体成分，需实现父类抽象方法，描述可通过构造器传入，价格简单返回固定值。Decorator（装饰器）所有其他成分（如猪肉、羊肉、青菜、芹菜等具有装饰功能成分）的父类。这是一个抽象类，其特征为必须有一个父类（Ingredient）作为成员变量，且必须继承公共父类（Ingredient）。Concrete Decorators（具体装饰器）如 Pork（猪肉）、Mutton（羊肉）、Celery（芹菜）、GreenGrocery（青菜）等。它们继承自 Decorator 类，通过构造器传入 Ingredient 实例。在实现 getDescription 和 getCost 方法时，不仅包含自身的描述和价格，还会加上被装饰成分的描述和价格，从而增强了被装饰成分的功能。3.2 代码实现以下是核心类的 Java 代码实现：Ingredient.javapublic abstract class Ingredient { public abstract String getDescription(); public abstract double getCost(); public void printDescription() { System.out.println(" Name " + this.getDescription(.html)); System.out.println(" Price RMB " + this.getCost(.html)); } }Bread.javapublic class Bread extends Ingredient { private String description; public Bread(String desc.html) { this.description = desc; } public String getDescription() { return description; } public double getCost() { return 2.48; } }Decorator.javapublic abstract class Decorator extends Ingredient { // 持有被装饰对象的引用 Ingredient ingredient; public Decorator(Ingredient igd.html) { this.ingredient = igd; } public abstract String getDescription(); public…

羽绒服割不动年轻人？Java代码教你“穿”出新选择！
type: item
date: 2026-07-09T04:37:25+00:00
description: 羽绒服割不动年轻人？Java 代码教你“穿”出新选择！在这个寒冷的冬天，羽绒服市场的变化如同编程语言的更新迭代一样引人注目。国产羽绒服价格飙升，让追求性价比的年轻人望而却步。正如羽绒服不再是年轻人的唯一保暖选择，在编程世界里，实现功能的方式也多种多样。今天，我们将通过 Java 代码探索如何让技术选型更加多样化，就像年轻人寻找羽绒服的“平替”一样，在保证核心功能的前提下追求更高的性价比。1. 羽绒服市场现状：品牌溢价与消费者选择如今，国产羽绒服的高端化转型使得价格一路看涨。除了原材料涨价的因素外，品牌溢价也占据了不小的比重。这让年轻人开始另寻他法：冲锋衣、防风服等成为了热门替代选择，甚至翻新旧羽绒服也成为一种趋势。在编程领域，Java 作为一种广泛应用的编程语言，也面临着类似的情况。开发者们在选择技术方案时，不再局限于传统的、可能成本较高（性能、资源等方面）的方式，而是寻求更高效、更经济的“替代方案”。2. Java 中的“保暖衣物”选择：接口与实现类在 Java 中，接口（Interface） 就像是一种标准规范，它定义了一组方法的签名，但不包含方法的实现。而 实现类（Implementation Class） 则是根据这个接口的规范来具体实现接口中的方法。就如同不同品牌的保暖衣物都遵循“保暖”这一基本功能标准一样。2.1 定义保暖衣物接口public interface WarmClothing { void keepWarm(); }这个 WarmClothing 接口定义了一个 keepWarm 方法，任何实现这个接口的类都必须提供这个方法的具体实现。2.2 羽绒服类（传统选择）public class DownJacket implements WarmClothing { @Override public void keepWarm() { System.out.println("羽绒服提供保暖功能，但价格较高。".html); } }这是传统的羽绒服类，它实现了 WarmClothing 接口，提供了保暖功能。在我们的类比中，它代表了价格较高（或资源消耗较大）的传统选择。2.3 冲锋衣类（“平替”选择）public class Windbreaker implements WarmClothing { @Override public void keepWarm() { System.out.println("冲锋衣也能提供保暖功能，且性价比更高。".html); } }冲锋衣类同样实现了 WarmClothing 接口。它就像是年轻人在 Java 编程中寻找的更具性价比的“平替”方案，能够以较低的成本（资源、性能等方面）实现相同的保暖（功能）需求。3. 选择合适的“衣物”：多态性的应用在 Java 中，多态性（Polymorphism） 允许我们根据对象的实际类型来调用相应的方法。这就好比在不同的天气和场景下，我们可以根据实际需求选择穿羽绒服还是冲锋衣。public class Main { public static void main(String[] args.html) { // 选择羽绒服 WarmClothing clothing1 = new DownJacket(); clothing1.keepWarm(); // 选择冲锋衣 WarmClothing clothing2 = new Windbreaker(); clothing2.keepWarm(); } }在上述代码中，我们创建了 DownJacket 和 Windbreaker 的对象，并将它们赋值给 WarmClothing 类型的变量。通过这种方式，我们可以根据需要灵活地选择不同的实现类，而无需修改调用代码。这就像我们在面对不同价格和性能的保暖衣物时，可以根据自己的需求（预算、保暖程度等）进行选择。4. 进一步优化：策略模式在实际应用中，我们可能需要根据更多的条件来选择合适的“保暖衣物”（实现类）。这时，我们可以引入 策略模式（Strategy Pattern） 来使代码更加灵活和可维护。4.1 定义策略接口public interface ClothingStrategy { WarmClothing chooseClothing(); }这个接口定义了一个 chooseClothing 方法，用于返回一个 WarmClothing 类型的对象。4.2 羽绒服策略类public class DownJacketStrategy implements ClothingStrategy { @Override public WarmClothing chooseClothing() { return new DownJacket()…

Tomcat 系统架构与设计模式
type: item
date: 2026-07-09T04:37:01+00:00
description: 门面设计模式门面设计模式（Facade Pattern）在 Tomcat 中有多处应用，例如 Request 和 Response 对象的封装、Standard Wrapper 到 ServletConfig 的封装、以及 ApplicationContext 到 ServletContext 的封装等。门面设计模式的原理门面设计模式的核心作用在于封装。顾名思义，就是将复杂的内部结构封装成一个统一的“门面”，以便与其他模块更便捷地进行交互，类似于国家外交部统一对外接口的角色。该模式主要应用于由多个子系统组成的大型系统中。子系统之间必然涉及相互通信，但每个子系统不应将内部数据过多地暴露给其他系统，否则划分子系统的意义将大打折扣。因此，每个子系统都会设计一个门面，将外部感兴趣的数据封装起来，并通过这个门面提供访问接口。这就是门面设计模式存在的意义。门面设计模式示意图如下：客户端（Client）仅能访问 Facade 提供的数据，这是门面设计模式的关键所在。至于 Client 如何访问 Facade，以及 Subsystem 如何提供 Facade，该模式并没有严格规定。Tomcat 的门面设计模式示例Tomcat 中包含众多不同组件，组件间需要相互交互数据，使用门面模式隔离数据是一种有效的方法。以下是 Request 对象上使用的门面设计模式示例：从类图可以看出，HttpRequestFacade 类封装了 HttpRequest 接口能够提供的数据。通过 HttpRequestFacade 访问到的数据都被代理到 HttpRequest 中。通常被封装的对象会被设为 Private 或者 Protected 访问修饰符，以防止在 Facade 之外被直接访问。观察者设计模式观察者设计模式（Observer Pattern）是一种常用的设计方法，通常也称为发布 - 订阅模式（Publish-Subscribe Pattern）或事件监听机制。它通常在某个事件发生的前后触发一些特定操作。观察者模式的原理观察者模式的原理相对简单：当主体（Subject）状态发生变化时，依赖该主体的观察者（Observer）会收到通知并执行相应操作。观察者必须向主体注册（登记），否则主体无法通知它。观察者模式通常包含以下几个角色：Subject（抽象主题）：负责管理所有观察者的引用，同时定义主要的事件操作。ConcreteSubject（具体主题）：实现抽象主题定义的所有接口，当自身状态发生变化时，通知所有观察者。Observer（观察者）：定义监听主题发生变化时的相应操作接口。Tomcat 的观察者模式示例Tomcat 中多处使用了观察者模式。前面提到的控制组件生命周期的 Lifecycle 接口就是这种模式的体现，此外 Servlet 实例的创建、Session 的管理、Container 的管理等都采用了同样的原理。下面主要看一下 Lifecycle 的具体实现。Lifecycle 的观察者模式结构图如下：在上述结构图中：LifecycleListener 代表抽象观察者，它定义了一个 lifecycleEvent 方法，这是当主题变化时要执行的方法。ServerLifecycleListener 代表具体观察者，它实现了 LifecycleListener 接口的方法。Lifecycle 接口代表抽象主题，它定义了管理观察者的方法以及其他相关方法。StandardServer 代表具体主题，它实现了抽象主题的所有方法。Tomcat 对观察者模式做了扩展，增加了两个辅助类：LifecycleSupport 和 LifecycleEvent。LifecycleEvent 使得可以定义事件类别，不同的事件可区别处理，更加灵活。LifecycleSupport 类代理了主题对多观察者的管理，将这个管理逻辑抽出来统一实现。以后如果需要修改，只需修改 LifecycleSupport 类，而不需要修改所有具体主题，因为所有具体主题对观察者的操作都被代理给了 LifecycleSupport 类。这可以认为是观察者模式的一种改进版。LifecycleSupport 调用观察者的方法代码如下：public void fireLifecycleEvent(String type, Object data.html) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data.html); LifecycleListener interested[] = null; synchronized (listeners.html) { interested = (LifecycleListener[…

Java设计模式——享元模式
type: item
date: 2026-07-09T04:36:58+00:00
description: 一、引子在 Java 中，String 类型具有一些独特的特性。其一，String 对象一旦被创建就不可改变（Immutable）；其二，当两个 String 对象所包含的内容相同时，JVM 通常只会创建一个 String 对象，这两个不同的对象引用将指向该同一对象。我们可以通过以下代码来验证这两个特性：public class TestPattern { public static void main(String[] args.html) { String n = "I Love Java"; String m = "I Love Java"; System.out.println(n == m.html); } }上述代码会输出 true，这表明在 JVM 中 n 和 m 两个引用指向了同一个 String 对象。若在系统输出之前添加一行代码 m = m + "hehe";，此时 n == m 的结果将变为 false。这是因为执行添加语句时，m 指向了一个新创建的 String 对象，而非修改原来引用的对象（因为 String 不可变）。String 类型的设计避免了创建大量相同内容的 String 对象时产生的不必要资源损耗，是享元模式（Flyweight Pattern）应用的范例。下面让我们深入学习享元模式。二、定义与分类享元模式英文称为"Flyweight Pattern"。其定义为：采用共享技术来避免大量拥有相同内容对象的开销，这里最常见、直观的开销就是内存损耗。享元模式以共享的方式高效支持大量细粒度对象。在该模式中，核心概念是共享。为实现共享，需要区分内蕴状态（Intrinsic State）和外蕴状态（Extrinsic State）：内蕴状态：是共性，存储在享元内部，不会随环境改变而不同，可共享。外蕴状态：是个性，随环境改变而改变，由客户端保持。在具体环境下，客户端将外蕴状态传递给享元以创建不同对象。根据《Java 与模式》，享元模式分为单纯享元模式和复合享元模式。（一）单纯享元模式结构抽象享元角色（Flyweight）：在 Java 中可由抽象类或接口担当，为具体享元角色规定必须实现的方法，外蕴状态以参数形式通过此方法传入。具体享元角色（Concrete Flyweight）：实现抽象角色规定的方法，若存在内蕴状态，负责为其提供存储空间。享元工厂角色（Flyweight Factory）：负责创建和管理享元角色，是实现共享的关键。其实现通常使用单例模式（Singleton），确保工厂对象只产生一个实例。客户端角色（Client）：维护对所有享元对象的引用，并存储对应的外蕴状态。单纯享元模式的类图如下：[此处可插入单纯享元模式类图，展示 Client、Flyweight、FlyweightFactory、ConcreteFlyweight 之间的关系]该模式结构类似简单工厂模式，但重点不同。简单工厂模式主要使系统不依赖于实现细节，而享元模式旨在采用共享技术避免大量相同内容对象的开销。举例（以咖啡店订单为例）假设一家咖啡店有多种口味的咖啡（如拿铁、摩卡、卡布奇诺等），接到大量订单时，咖啡口味可设置为共享，不必为每一杯单独生成对象。以下是相关代码实现：import java.util.*; // 抽象订单类 public abstract class Order { // 执行卖出动作 public abstract void sell(); } // 具体口味订单类 public class FlavorOrder extends Order { public String flavor; // 获取咖啡口味 public FlavorOrder(String flavor.html) { this.flavor = flavor; } @Override public void sell() { System.out.println("卖出一份" + flavor + "的咖啡。".html); } } // 口味工厂类 public class FlavorFactory { private Map<String, Order> flavorPool = new HashMap<>(); // 静态工厂，负责生成订单对象 private static final FlavorFactory flavorFactory = new FlavorFactory(); private FlavorFactory() { } public static FlavorFactory getInstance() { return flavorFactory; } public Order getOrder(Str…

Java设计模式——策略、代理模式
type: item
date: 2026-07-09T04:36:34+00:00
description: 策略模式概述定义与概念策略模式（Strategy Pattern）属于对象行为型模式。其核心思想是针对一组算法，将每个算法封装到具有共同接口的独立类中，从而实现它们之间的互相替换。该模式将算法的责任和算法本身分隔开，委派给不同的对象管理，把算法包装到一系列的策略类里面，作为一个抽象策略类的子类。简单来说，就是准备一组算法，并将每一个算法封装起来，使它们可以互换。模式角色环境类（Context）：持有一个 Strategy 类的引用。它是策略模式的使用场景，负责调用具体策略类的算法接口来完成特定的任务。例如，在一个游戏中，游戏角色的移动行为可以看作是一个环境，它可能持有不同移动策略（如步行策略、飞行策略等）的引用，根据游戏场景的不同选择合适的移动策略。抽象策略类（Strategy）：这是一个抽象角色，通常由一个接口或抽象类实现。此角色给出了所有具体策略类所需要的接口，定义了算法的规范。具体的策略类必须实现这个接口，以保证算法的一致性和可替换性。具体策略类（Concrete Strategy）：包装了相关的算法和行为，实现了抽象策略类定义的接口，提供了具体的算法实现。比如，在上述游戏中，步行策略类和飞行策略类就是具体策略类，它们分别实现了移动算法的不同方式。代码实现环境类（Context）public class Context { // 持有策略类的引用 private Strategy strategy; // 设置策略类的方法 public void setStrategy(Strategy strategy.html) { this.strategy = strategy; } // 调用策略类的算法接口 public void contextInterface() { strategy.strategyInterface(); } }抽象策略类（Strategy）public abstract class Strategy { // 抽象的算法接口 public abstract void strategyInterface(); }具体策略类（ConcreteStrategy）public class ConcreteStrategyA extends Strategy { @Override public void strategyInterface() { // 实现具体的算法 A System.out.println("执行算法 A".html); } } public class ConcreteStrategyB extends Strategy { @Override public void strategyInterface() { // 实现具体的算法 B System.out.println("执行算法 B".html); } }特点与优势算法独立性与可扩展性策略模式使得每个算法都独立封装在一个类中，与其他算法互不干扰。当需要添加新的算法时，只需要创建一个新的具体策略类并实现抽象策略接口即可，不会影响到现有的代码结构。例如，如果在游戏中要添加一种新的移动方式，如游泳策略，只需要创建一个 SwimmingStrategy 类并实现 Strategy 接口。高内聚低耦合策略模式实现了高内聚低耦合。每个策略类专注于实现自己的算法，职责单一，内聚性高。同时，环境类与具体策略类之间通过抽象策略接口耦合，降低了它们之间的依赖关系，使得系统更加灵活和易于维护。当业务需求发生变化时，只需要调整或替换相应的策略类，而不需要大规模修改环境类或其他相关代码。应用场景游戏开发中的行为控制如前面提到的游戏角色的移动、攻击等行为可以采用策略模式。不同的角色可能有不同的攻击策略（如近战攻击、远程攻击等），通过策略模式可以方便地实现和切换这些攻击方式，提高游戏的可玩性和灵活性。电商系统中的促销策略在电商系统中，根据不同的促销活动，商品的计价方式可能不同。例如，有满减策略、折扣策略、赠品策略等。使用策略模式可以将这些不同的计价算法封装成具体策略类，根据促销活动的规则选择合适的策略来计算商品价格，方便系统的扩展和维护。代理模式概述概念解释代理模式可以用生活中的例子来理解，比如“我很忙，忙得没空理你，那你要找我呢就先找我的代理人吧”。在这个场景中，代理人和被代理人具备同一个接口，代理人虽然不能直接干活，但是知道被代理的人能做哪些事情、不能做哪些事情。代理模式就是在这种情况下，通过代理对象来控制对真实对象的访问。模式结构抽象主题角色（Subject）：声明了代理主题和真实主题的共同接口，这样一来在任何可以使用真实主题的地方都可以使用代理主题。它定义了真实主题和代理主题都需要实现的方法，使得客户端可以以统一的方式调用真实主题和代理主题的操作。…