分类
创建型模式 Creational
Patterns
单例模式(Singleton)
确保类只有一个实例,并提供全局访问点。
工厂方法(Factory Method)
定义创建对象的接口,由子类决定实例化。
抽象工厂(Abstract Factory)
创建一系列相关对象的工厂。
建造者(Builder)
分步构造复杂对象。
原型模式(Prototype)
通过克隆创建新对象。
结构型模式 Structural
Patterns
适配器(Adapter)
将不兼容的接口转换为兼容接口。
桥接(Bridge)
将抽象与实现分离。
组合(Composite)
将对象组织成树形结构。
装饰者(Decorator)
动态扩展对象功能。
外观(Facade)
为复杂子系统提供简单接口。
享元(Flyweight)
共享细粒度对象以节省资源。
代理(Proxy)
控制对对象的访问。
行为型模式 Behavioral
Patterns
责任链(Chain of Responsibility)
将请求沿处理链传递。
命令(Command)
将请求封装为对象。
解释器(Interpreter)
定义语言的解释规则。
迭代器(Iterator)
顺序访问集合元素。
中介者(Mediator)
通过中介协调对象交互。
备忘录(Memento)
保存和恢复对象状态。
观察者(Observer)
对象状态变化时通知依赖者。
状态(State)
根据状态改变对象行为。
策略(Strategy)
定义可互换的算法家族。
模板方法(Template Method)
定义算法骨架,子类实现细节。
访问者(Visitor)
在不修改类的情况下增加新操作。
扩展模式 Extended
Patterns
依赖注入(Dependency Injection)
通过外部注入依赖,解耦组件。
发布-订阅(Publish-Subscribe)
事件驱动的观察者变种。
模块模式(Module Pattern)
封装代码,管理私有/公有成员。
MVC(Model-View-Controller)
分离数据(Model)、界面(View)和逻辑(Controller)。
MVP(Model-View-Presenter)
View 和 Presenter 交互,Model
隔离数据。
MVVM(Model-View-ViewModel)
通过 ViewModel 绑定 Model 和 View。
仓储模式(Repository Pattern)
封装数据访问逻辑。
服务定位器(Service Locator)
集中管理服务实例的获取。
事件溯源(Event Sourcing)
通过事件记录对象状态。
图示
graph LR
A[设计模式<br>Design Patterns]
A --> B[创建型模式<br>Creational Patterns]
B --> B1[单例模式<br>Singleton]
B --> B2[工厂方法<br>Factory Method]
B --> B3[抽象工厂<br>Abstract Factory]
B --> B4[建造者<br>Builder]
B --> B5[原型模式<br>Prototype]
A --> C[结构型模式<br>Structural Patterns]
C --> C1[适配器<br>Adapter]
C --> C2[桥接<br>Bridge]
C --> C3[组合<br>Composite]
C --> C4[装饰者<br>Decorator]
C --> C5[外观<br>Facade]
C --> C6[享元<br>Flyweight]
C --> C7[代理<br>Proxy]
A --> D[行为型模式<br>Behavioral Patterns]
D --> D1[责任链<br>Chain of Responsibility]
D --> D2[命令<br>Command]
D --> D3[解释器<br>Interpreter]
D --> D4[迭代器<br>Iterator]
D --> D5[中介者<br>Mediator]
D --> D6[备忘录<br>Memento]
D --> D7[观察者<br>Observer]
D --> D8[状态<br>State]
D --> D9[策略<br>Strategy]
D --> D10[模板方法<br>Template Method]
D --> D11[访问者<br>Visitor]
A --> E[扩展模式<br>Extended Patterns]
E --> E1[依赖注入<br>Dependency Injection]
E --> E2[发布-订阅<br>Publish-Subscribe]
E --> E3[模块模式<br>Module Pattern]
E --> E4[MVC<br>Model-View-Controller]
E --> E5[MVP<br>Model-View-Presenter]
E --> E6[MVVM<br>Model-View-ViewModel]
E --> E7[仓储模式<br>Repository Pattern]
E --> E8[服务定位器<br>Service Locator]
E --> E9[事件溯源<br>Event Sourcing]
详解
创建型模式(Creational
Patterns)
单例模式(Singleton)
单例模式(Singleton
Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。以下是单例模式的各种实现方式,包括线程安全的版本,用
Java 编写。每种实现都会标注其特点、优缺点及适用场景。
1. 饿汉式(Eager
Initialization)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SingletonEager { private static final SingletonEager INSTANCE = new SingletonEager (); private SingletonEager () { if (INSTANCE != null ) { throw new RuntimeException ("Singleton instance already exists" ); } } public static SingletonEager getInstance () { return INSTANCE; } }
特点 :类加载时即创建实例,线程安全。
优点 :简单,无需同步,天然线程安全。
缺点 :无论是否使用,都会创建实例,可能浪费资源。
适用场景 :实例开销小,且肯定会被使用。
2. 懒汉式(Lazy
Initialization,非线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SingletonLazy { private static SingletonLazy instance; private SingletonLazy () { if (instance != null ) { throw new RuntimeException ("Singleton instance already exists" ); } } public static SingletonLazy getInstance () { if (instance == null ) { instance = new SingletonLazy (); } return instance; } }
特点 :延迟加载,第一次调用时创建实例。
优点 :节省资源,懒加载。
缺点 :非线程安全,多线程下可能创建多个实例。
适用场景 :单线程环境,或不在意线程安全。
添加标志位:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class SingletonLazyWithFlag { private static SingletonLazyWithFlag instance; private static volatile boolean initialized = false ; private SingletonLazyWithFlag () { synchronized (SingletonLazyWithFlag.class) { if (initialized) { throw new RuntimeException ("Singleton instance already exists" ); } initialized = true ; } } public static SingletonLazyWithFlag getInstance () { if (instance == null ) { synchronized (SingletonLazyWithFlag.class) { if (instance == null ) { instance = new SingletonLazyWithFlag (); } } } return instance; } }
3.
线程安全的懒汉式(Synchronized 方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SingletonSyncMethod { private static SingletonSyncMethod instance; private SingletonSyncMethod () { if (instance != null ) { throw new RuntimeException ("Singleton instance already exists" ); } } public static synchronized SingletonSyncMethod getInstance () { if (instance == null ) { instance = new SingletonSyncMethod (); } return instance; } }
特点 :通过同步方法实现线程安全。
优点 :简单,保证线程安全。
缺点 :每次调用 getInstance
都要加锁,性能开销大。
适用场景 :多线程环境,但调用频率不高。
4.
双重检查锁(Double-Checked Locking, DCL)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class SingletonDCL { private static volatile SingletonDCL instance; private SingletonDCL () { if (instance != null ) { throw new RuntimeException ("Singleton instance already exists" ); } } public static SingletonDCL getInstance () { if (instance == null ) { synchronized (SingletonDCL.class) { if (instance == null ) { instance = new SingletonDCL (); } } } return instance; } }
特点 :结合懒加载和线程安全,双重检查减少同步开销。
优点 :高效,只有在实例未创建时加锁。
缺点 :实现复杂,需使用 volatile
(Java
5+)防止指令重排。
适用场景 :多线程环境,追求性能优化。
5. 静态内部类(Static Inner
Class)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class SingletonStaticInner { private SingletonStaticInner () { if (SingletonHolder.INSTANCE != null ) { throw new RuntimeException ("Singleton instance already exists" ); } } private static class SingletonHolder { private static final SingletonStaticInner INSTANCE = new SingletonStaticInner (); } public static SingletonStaticInner getInstance () { return SingletonHolder.INSTANCE; } }
特点 :利用类加载机制实现懒加载和线程安全。
优点 :简单、高效,JVM
保证线程安全,无需显式同步。
缺点 :无法传递构造参数。
适用场景 :多线程环境,推荐的懒加载方式。
6. 枚举单例(Enum Singleton)
1 2 3 4 5 6 7 8 public enum SingletonEnum { INSTANCE; public void doSomething () { System.out.println("SingletonEnum is working" ); } }
用法 : 1 2 SingletonEnum singleton = SingletonEnum.INSTANCE;singleton.doSomething();
特点 :使用枚举实现单例,JVM 保证唯一性。
优点 :最简单,天然线程安全,防止反射和序列化破坏。
缺点 :无法懒加载,枚举类加载时即创建。
适用场景 :需要绝对安全(如防止反射攻击)的场景。
7. ThreadLocal
单例(线程局部单例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class SingletonThreadLocal { private static final ThreadLocal<SingletonThreadLocal> THREAD_LOCAL = ThreadLocal.withInitial(SingletonThreadLocal::new ); private SingletonThreadLocal () { } public static SingletonThreadLocal getInstance () { return THREAD_LOCAL.get(); } public static void remove () { THREAD_LOCAL.remove(); } }
特点 :每个线程拥有独立的单例实例。
优点 :线程隔离,适合线程特定的单例需求。
缺点 :不是全局单例,需注意 ThreadLocal
的内存管理。
适用场景 :线程私有单例,如线程上下文管理。
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Main { public static void main (String[] args) { SingletonEager s1 = SingletonEager.getInstance(); SingletonEager s2 = SingletonEager.getInstance(); System.out.println("Eager: " + (s1 == s2)); Runnable task = () -> System.out.println("DCL: " + SingletonDCL.getInstance()); Thread t1 = new Thread (task); Thread t2 = new Thread (task); t1.start(); t2.start(); SingletonEnum e1 = SingletonEnum.INSTANCE; SingletonEnum e2 = SingletonEnum.INSTANCE; System.out.println("Enum: " + (e1 == e2)); Thread thread1 = new Thread (() -> { SingletonThreadLocal stl1 = SingletonThreadLocal.getInstance(); System.out.println("ThreadLocal Thread1: " + stl1); }); Thread thread2 = new Thread (() -> { SingletonThreadLocal stl2 = SingletonThreadLocal.getInstance(); System.out.println("ThreadLocal Thread2: " + stl2); }); thread1.start(); thread2.start(); } }
说明
线程安全 :
饿汉式、静态内部类、枚举天然线程安全。
懒汉式需加锁(同步方法或 DCL)实现线程安全。
ThreadLocal 为每个线程提供独立实例。
反射和序列化防护 :
枚举单例天然防止反射和序列化破坏。
其他实现通过检查实例是否存在(构造方法抛异常)防御反射。
序列化需实现 readResolve
方法: 1 2 3 private Object readResolve () { return getInstance(); }
性能 :
饿汉式和枚举无延迟,静态内部类和 DCL 高效懒加载。
同步方法性能较低。
复杂度 :
总结表
饿汉式
否
是
低
是
需额外实现
简单实例
懒汉式
是
否
低
是
需额外实现
单线程
同步方法
是
是
中
是
需额外实现
调用不频繁
双重检查锁
是
是
高
是
需额外实现
高性能多线程
静态内部类
是
是
中
是
需额外实现
推荐的多线程懒加载
枚举
否
是
低
是
是
最高安全性
ThreadLocal
是
线程内
中
是
需额外实现
线程私有单例
如何防止序列化破坏
为什么会发生序列化破坏:如果一个单例类实现了 Serializable
接口,反序列化时会通过反射创建一个新实例,而不是返回现有的单例实例。这会导致系统中存在多个实例,破坏单例的唯一性。
在单例类中添加 readResolve 方法,反序列化时 JVM
会调用此方法,返回指定的对象,而不是新建的实例。或者使用枚举。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.io.*;public class Singleton implements Serializable { private static final Singleton INSTANCE = new Singleton (); private Singleton () {} public static Singleton getInstance () { return INSTANCE; } private Object readResolve () { return INSTANCE; } } class Test { public static void main (String[] args) throws Exception { Singleton s1 = Singleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("singleton.ser" )); oos.writeObject(s1); oos.close(); ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("singleton.ser" )); Singleton s2 = (Singleton) ois.readObject(); ois.close(); System.out.println("s1 == s2: " + (s1 == s2)); } }
工厂方法(Factory
Method)
工厂方法模式(Factory Method
Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但将具体的对象实例化推迟到子类中实现。相比简单工厂模式,工厂方法模式通过将对象的创建交给具体的工厂类,提升了灵活性和扩展性,遵循了“开闭原则”(对扩展开放,对修改关闭)。
以下是用 Java
实现工厂方法模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 工厂方法模式的定义
核心思想 :定义一个创建对象的接口(工厂方法),由子类决定具体实例化哪种产品。
目的 :
解耦客户端与具体产品类。
让子类决定创建哪种对象,增加系统的可扩展性。
适用场景 :
需要生成的产品种类较多,且可能新增类型。
客户端不关心对象的具体创建过程,只关心接口。
2. 工厂方法模式的结构
抽象产品(Product) :定义产品的接口,所有具体产品实现此接口。
具体产品(Concrete
Product) :实现抽象产品接口的具体类。
抽象工厂(Creator) :声明工厂方法,返回抽象产品类型。
具体工厂(Concrete
Creator) :实现工厂方法,创建具体产品实例。
UML 图
classDiagram
class Product {
<<interface>>
+operation() void
}
class ConcreteProduct {
+operation() void
}
class Creator {
<<abstract>>
+factoryMethod() Product
}
class ConcreteCreator {
+factoryMethod() Product
}
ConcreteProduct ..|> Product : implements
ConcreteCreator --|> Creator : extends
ConcreteCreator o--> "1" ConcreteProduct : creates
3. Java 实现示例
以下是一个生产不同类型车辆的工厂方法模式示例:
3.1 抽象产品接口
1 2 3 4 public interface Vehicle { void drive () ; }
3.2 具体产品类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Car implements Vehicle { @Override public void drive () { System.out.println("Driving a car" ); } } public class Motorcycle implements Vehicle { @Override public void drive () { System.out.println("Riding a motorcycle" ); } }
3.3 抽象工厂类
1 2 3 4 5 6 7 8 9 10 11 12 public abstract class VehicleFactory { public abstract Vehicle createVehicle () ; public Vehicle getVehicle () { Vehicle vehicle = createVehicle(); vehicle.drive(); return vehicle; } }
3.4 具体工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class CarFactory extends VehicleFactory { @Override public Vehicle createVehicle () { return new Car (); } } public class MotorcycleFactory extends VehicleFactory { @Override public Vehicle createVehicle () { return new Motorcycle (); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 public class Main { public static void main (String[] args) { VehicleFactory carFactory = new CarFactory (); Vehicle car = carFactory.getVehicle(); VehicleFactory motorcycleFactory = new MotorcycleFactory (); Vehicle motorcycle = motorcycleFactory.getVehicle(); } }
4. 工作原理
客户端 选择具体的工厂类(CarFactory
或
MotorcycleFactory
)。
调用工厂的 createVehicle()
方法,创建具体产品(Car
或 Motorcycle
)。
返回的 Vehicle
对象由客户端使用,客户端无需知道具体产品类。
5. 优点
灵活性 :新增产品只需添加新产品类和对应的工厂类,无需修改现有代码。
解耦 :客户端只依赖抽象接口(Vehicle
和
VehicleFactory
),不关心具体实现。
单一职责 :每个工厂负责创建一种产品,职责清晰。
6. 缺点
类数量增加 :每增加一种产品,就需要新增一个具体产品类和一个具体工厂类,导致类数量增多。
复杂度提升 :相比简单工厂模式,代码结构更复杂。
7. 与简单工厂的对比
简单工厂(非工厂方法模式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SimpleVehicleFactory { public static Vehicle createVehicle (String type) { if ("car" .equals(type)) { return new Car (); } else if ("motorcycle" .equals(type)) { return new Motorcycle (); } return null ; } } class Main { public static void main (String[] args) { Vehicle car = SimpleVehicleFactory.createVehicle("car" ); car.drive(); } }
区别 :
简单工厂将创建逻辑集中在一个类中,违反“开闭原则”(新增类型需修改工厂类)。
工厂方法将创建逻辑分散到子类中,符合“开闭原则”。
8. 扩展示例:带参数的工厂方法
如果需要根据参数创建不同配置的产品,可以这样扩展:
修改抽象工厂
1 2 3 public abstract class VehicleFactory { public abstract Vehicle createVehicle (String color) ; }
修改具体工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CarFactory extends VehicleFactory { @Override public Vehicle createVehicle (String color) { return new Car (color); } } public class Car implements Vehicle { private String color; public Car (String color) { this .color = color; } @Override public void drive () { System.out.println("Driving a " + color + " car" ); } }
客户端
1 2 3 4 5 6 7 public class Main { public static void main (String[] args) { VehicleFactory carFactory = new CarFactory (); Vehicle redCar = carFactory.createVehicle("red" ); redCar.drive(); } }
9. 实际应用场景
日志框架 :如 SLF4J 的
LoggerFactory
,根据配置创建不同类型的日志记录器。
数据库连接 :根据驱动类型创建不同的
Connection
对象。
UI 组件 :根据主题创建不同样式的按钮或窗口。
10. 源码中的例子
Java 中的 java.util.Calendar
使用了类似工厂方法模式:
1 Calendar calendar = Calendar.getInstance();
- Calendar
是抽象类,getInstance()
根据区域和时区返回具体子类(如
GregorianCalendar
)。
总结
工厂方法模式 通过抽象工厂接口和具体工厂类实现对象的创建,提供了扩展性和解耦性。
Java
实现 的关键是定义抽象产品和工厂接口,然后由具体子类实现。
核心优势 是支持新增产品而无需修改现有代码。
抽象工厂(Abstract
Factory)
抽象工厂模式(Abstract Factory
Pattern)是一种创建型设计模式,它提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体类。与工厂方法模式不同,抽象工厂模式关注于创建一组相关的产品(产品族),适用于需要统一风格或兼容性对象的场景。
以下是用 Java
实现抽象工厂模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 抽象工厂模式的定义
核心思想 :定义一个抽象工厂接口,创建一组相关产品的对象,具体工厂类实现该接口,生成具体产品。
目的 :
将一组相关产品的创建封装起来,确保产品之间的兼容性。
解耦客户端与具体产品类,客户端只依赖抽象接口。
适用场景 :
需要创建多个相关对象(如 UI 组件、数据库访问对象)。
系统需要支持多种产品族(如不同风格的主题或配置)。
2. 抽象工厂模式的结构
抽象产品接口(Abstract
Product) :定义每个产品类型的接口。
具体产品(Concrete
Product) :实现抽象产品接口的具体类。
抽象工厂(Abstract
Factory) :声明一组创建产品的方法。
具体工厂(Concrete
Factory) :实现抽象工厂接口,创建一组具体产品。
UML 图
classDiagram
class AbstractProductA {
+operationA()
}
class ConcreteProductA {
+operationA()
}
class AbstractProductB {
+operationB()
}
class ConcreteProductB {
+operationB()
}
class AbstractFactory {
+createProductA() AbstractProductA
+createProductB() AbstractProductB
}
class ConcreteFactory {
+createProductA() AbstractProductA
+createProductB() AbstractProductB
}
ConcreteProductA --|> AbstractProductA
ConcreteProductB --|> AbstractProductB
ConcreteFactory --|> AbstractFactory
ConcreteFactory --> ConcreteProductA
ConcreteFactory --> ConcreteProductB
3. Java 实现示例
以下是一个生产 UI
组件(按钮和文本框)的抽象工厂模式示例,支持不同风格(如 Windows 和
Mac)。
3.1 抽象产品接口
1 2 3 4 5 6 7 8 9 public interface Button { void render () ; } public interface TextField { void input () ; }
3.2 具体产品类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class WindowsButton implements Button { @Override public void render () { System.out.println("Rendering a Windows button" ); } } public class WindowsTextField implements TextField { @Override public void input () { System.out.println("Input in a Windows text field" ); } } public class MacButton implements Button { @Override public void render () { System.out.println("Rendering a Mac button" ); } } public class MacTextField implements TextField { @Override public void input () { System.out.println("Input in a Mac text field" ); } }
3.3 抽象工厂接口
1 2 3 4 5 public interface UIFactory { Button createButton () ; TextField createTextField () ; }
3.4 具体工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class WindowsUIFactory implements UIFactory { @Override public Button createButton () { return new WindowsButton (); } @Override public TextField createTextField () { return new WindowsTextField (); } } public class MacUIFactory implements UIFactory { @Override public Button createButton () { return new MacButton (); } @Override public TextField createTextField () { return new MacTextField (); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Main { public static void main (String[] args) { UIFactory windowsFactory = new WindowsUIFactory (); Button windowsButton = windowsFactory.createButton(); TextField windowsText = windowsFactory.createTextField(); windowsButton.render(); windowsText.input(); UIFactory macFactory = new MacUIFactory (); Button macButton = macFactory.createButton(); TextField macText = macFactory.createTextField(); macButton.render(); macText.input(); } }
4. 工作原理
客户端 选择一个具体工厂(如
WindowsUIFactory
或 MacUIFactory
)。
调用工厂的创建方法(createButton()
和
createTextField()
),生成一组相关产品。
客户端使用这些产品,保持风格一致性(如 Windows
风格的按钮和文本框)。
5. 优点
一致性 :保证创建的产品属于同一产品族,兼容性强。
扩展性 :新增产品族只需增加新的具体工厂和产品类,符合“开闭原则”。
解耦 :客户端只依赖抽象工厂和产品接口,不关心具体实现。
6. 缺点
复杂度高 :需要定义多个抽象产品和具体工厂,类数量较多。
不易扩展产品 :如果产品族中的产品种类增加(如新增
Checkbox),需要修改抽象工厂接口及其所有实现类,违反“开闭原则”。
7. 与工厂方法的对比
创建对象
单个产品
一组相关产品(产品族)
扩展性
易扩展新产品种类
易扩展新产品族
复杂度
较低
较高
抽象层级
一个工厂方法
多个创建方法
工厂方法 :关注单一产品的创建(如只创建按钮)。
抽象工厂 :关注一组相关产品的创建(如按钮和文本框的组合)。
8. 扩展示例:带参数
如果需要根据参数创建产品,可以这样扩展:
修改抽象工厂
1 2 3 4 public interface UIFactory { Button createButton (String style) ; TextField createTextField (String style) ; }
修改具体工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class WindowsUIFactory implements UIFactory { @Override public Button createButton (String style) { return new WindowsButton (style); } @Override public TextField createTextField (String style) { return new WindowsTextField (style); } } public class WindowsButton implements Button { private String style; public WindowsButton (String style) { this .style = style; } @Override public void render () { System.out.println("Rendering a Windows button with style: " + style); } }
客户端
1 2 3 4 5 6 7 public class Main { public static void main (String[] args) { UIFactory factory = new WindowsUIFactory (); Button button = factory.createButton("modern" ); button.render(); } }
9. 实际应用场景
GUI 框架 :如 Swing 或
JavaFX,创建不同平台的组件(如 Windows 和 Mac 风格的按钮、窗口)。
数据库访问 :创建一组数据库操作对象(如连接、语句、结果集),支持
MySQL、Oracle 等。
游戏开发 :创建不同主题的资源(如森林主题的树木和动物)。
10. 源码中的例子
Java 中的 java.sql.DriverManager
和 JDBC
驱动有一些抽象工厂的影子: 1 Connection conn = DriverManager.getConnection(url);
- 根据驱动类型,创建对应的
Connection
、Statement
等对象。
总结
抽象工厂模式 通过抽象工厂接口创建一组相关产品,适用于产品族场景。
Java
实现 的关键是定义抽象产品和工厂接口,由具体工厂实现产品创建。
核心优势 是保证产品一致性和支持产品族的扩展。
如果你需要更复杂的例子(如多产品族)或 UML 图,请告诉我!
建造者(Builder)
建造者模式(Builder
Pattern)是一种创建型设计模式,用于分步构建复杂对象。它将对象的构造过程与其表示分离,使得同样的构建过程可以创建不同的表示。建造者模式特别适合需要多个步骤配置的对象,例如对象有多个可选属性或复杂的初始化逻辑。
以下是用 Java 实现建造者模式的详细讲解,并附上用 Mermaid 绘制的 UML
类图。
1. 建造者模式的定义
核心思想 :通过一个建造者(Builder)逐步构造复杂对象,最终由指挥者(Director)或直接调用建造者生成产品。
目的 :
分离对象的构造和表示,便于灵活配置。
避免构造函数参数过多(“望远镜构造函数”问题)。
适用场景 :
对象有多个可选属性或复杂初始化步骤。
需要创建不可变对象。
构造过程需要复用。
2. 建造者模式的结构
产品(Product) :最终要构建的复杂对象。
抽象建造者(Builder) :定义构建产品各部分的抽象方法。
具体建造者(Concrete
Builder) :实现抽象建造者,逐步构造产品并提供获取结果的方法。
指挥者(Director) :可选,负责控制建造过程,调用建造者的方法。
UML 图
classDiagram
class Product {
-field1
-field2
}
class Builder {
+buildPart1()
+buildPart2()
+getResult() Product
}
class ConcreteBuilder {
-product: Product
+buildPart1()
+buildPart2()
+getResult() Product
}
class Director {
-builder: Builder
+construct()
}
ConcreteBuilder --> Product : builds
ConcreteBuilder ..|> Builder : implements
Director --> Builder : uses
3. Java 实现示例
以下是一个构建房屋(House)的建造者模式示例。
3.1 产品类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class House { private String foundation; private String structure; private String roof; public void setFoundation (String foundation) { this .foundation = foundation; } public void setStructure (String structure) { this .structure = structure; } public void setRoof (String roof) { this .roof = roof; } @Override public String toString () { return "House [foundation=" + foundation + ", structure=" + structure + ", roof=" + roof + "]" ; } }
3.2 抽象建造者接口
1 2 3 4 5 6 7 public interface HouseBuilder { void buildFoundation () ; void buildStructure () ; void buildRoof () ; House getResult () ; }
3.3 具体建造者类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class WoodenHouseBuilder implements HouseBuilder { private House house; public WoodenHouseBuilder () { this .house = new House (); } @Override public void buildFoundation () { house.setFoundation("Wooden foundation" ); } @Override public void buildStructure () { house.setStructure("Wooden walls" ); } @Override public void buildRoof () { house.setRoof("Wooden roof" ); } @Override public House getResult () { return house; } }
3.4 指挥者类(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class HouseDirector { private HouseBuilder builder; public HouseDirector (HouseBuilder builder) { this .builder = builder; } public House construct () { builder.buildFoundation(); builder.buildStructure(); builder.buildRoof(); return builder.getResult(); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Main { public static void main (String[] args) { HouseBuilder woodenBuilder = new WoodenHouseBuilder (); HouseDirector director = new HouseDirector (woodenBuilder); House house = director.construct(); System.out.println(house); HouseBuilder builder = new WoodenHouseBuilder (); builder.buildFoundation(); builder.buildStructure(); builder.buildRoof(); House house2 = builder.getResult(); System.out.println(house2); } }
4. 工作原理
客户端 选择一个具体建造者(如
WoodenHouseBuilder
)。
通过指挥者(可选)或直接调用建造者的方法,逐步构建产品(设置地基、结构、屋顶)。
调用 getResult()
获取最终产品。
5. 优点
分步构造 :将复杂对象的创建分解为多个步骤,清晰可控。
灵活性 :支持不同的构造过程和产品表示。
封装性 :隐藏产品的内部构造细节。
6. 缺点
类数量增加 :需要为每种产品定义建造者,增加代码量。
适用范围有限 :适合复杂对象,不适合简单对象。
7. 与工厂模式的对比
关注点
创建单一对象
分步构建复杂对象
过程
一步完成
多步配置
结果
直接返回产品
构建完成后返回产品
9. 实际应用场景
字符串构建 :StringBuilder
是建造者模式的典型例子。
对象配置 :如 OkHttpClient.Builder
或
AlertDialog.Builder
。
文档生成 :如生成复杂的 PDF 或 HTML 文档。
10. 源码中的例子
Java 中的 StringBuilder
: 1 2 3 StringBuilder builder = new StringBuilder ();builder.append("Hello" ).append(" " ).append("World" ); String result = builder.toString();
总结
建造者模式 通过分步构建复杂对象,提供灵活性和封装性。
Java
实现 的关键是定义建造者接口和产品类,指挥者可选。
Mermaid UML 展示了核心结构,清晰表达模式关系。
如果需要更复杂的例子(如多个建造者)或调整 UML 图,请告诉我!
原型模式(Prototype)
原型模式(Prototype
Pattern)是一种创建型设计模式,通过复制现有对象(原型)来创建新对象,而不是通过构造函数从头构建。它适用于创建对象成本较高(如需要大量计算或资源)或需要基于现有对象快速生成类似对象的场景。
以下是用 Java 实现原型模式的详细讲解,并附上用 Mermaid 绘制的 UML
类图。
1. 原型模式的定义
核心思想 :通过克隆已有对象(原型)创建新对象,而不是通过
new
实例化。
目的 :
提高创建效率,避免重复的初始化工作。
支持动态生成对象副本。
适用场景 :
对象创建复杂或耗时。
需要创建大量相似对象。
需要对象深拷贝或浅拷贝。
2. 原型模式的结构
抽象原型(Prototype) :定义克隆方法的接口。
具体原型(Concrete
Prototype) :实现克隆方法,复制自身。
客户端(Client) :使用原型创建新对象。
UML 图
classDiagram
class Prototype {
+clone() Prototype
}
class ConcretePrototype {
-field1
-field2
+clone() Prototype
}
class Client {
-prototype: Prototype
}
ConcretePrototype ..|> Prototype : implements
Client --> Prototype : uses
ConcretePrototype --> ConcretePrototype : clones
3. Java 实现示例
以下是一个形状(Shape)的原型模式示例,支持克隆圆形对象。
3.1 抽象原型接口
1 2 3 4 5 public interface Shape extends Cloneable { Shape clone () ; void draw () ; }
3.2 具体原型类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Circle implements Shape { private int radius; private String color; public Circle (int radius, String color) { this .radius = radius; this .color = color; } public void setRadius (int radius) { this .radius = radius; } public void setColor (String color) { this .color = color; } @Override public Shape clone () { try { return (Shape) super .clone(); } catch (CloneNotSupportedException e) { return null ; } } @Override public void draw () { System.out.println("Drawing a " + color + " circle with radius " + radius); } }
3.3 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Main { public static void main (String[] args) { Circle original = new Circle (10 , "red" ); original.draw(); Circle cloned = (Circle) original.clone(); cloned.setColor("blue" ); cloned.draw(); original.draw(); } }
4. 工作原理
客户端 创建初始原型对象(如
Circle
)。
调用 clone()
方法生成副本。
修改副本的属性,保持原对象不变。
5. 深拷贝 vs 浅拷贝
浅拷贝 (如上例):
使用
Object.clone()
,只复制对象本身,引用类型字段仍指向原对象。
如果原型包含复杂对象(如列表),副本修改会影响原对象。
深拷贝 :
深拷贝示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Circle implements Shape { private int radius; private String color; private List<String> tags; public Circle (int radius, String color, List<String> tags) { this .radius = radius; this .color = color; this .tags = tags; } @Override public Shape clone () { try { Circle cloned = (Circle) super .clone(); cloned.tags = new ArrayList <>(this .tags); return cloned; } catch (CloneNotSupportedException e) { return null ; } } @Override public void draw () { System.out.println("Drawing a " + color + " circle with radius " + radius + ", tags: " + tags); } public void setTags (List<String> tags) { this .tags = tags; } }
6. 优点
性能提升 :避免重复初始化,适合复杂对象。
灵活性 :动态创建对象副本,可修改副本而不影响原型。
简化创建 :无需复杂构造函数。
7. 缺点
实现复杂性 :深拷贝需要手动实现,浅拷贝可能导致意外副作用。
依赖 Cloneable
:Java
的克隆机制不够灵活,异常处理麻烦。
8. 与工厂模式的对比
创建方式
通过类实例化
通过复制现有对象
初始化
从头构建
基于原型克隆
适用性
创建新对象
复制已有对象
10. 实际应用场景
对象缓存 :缓存复杂对象,通过克隆提供副本。
图形编辑器 :复制图形元素(如矩形、圆形)。
游戏开发 :克隆敌人或道具对象。
11. 源码中的例子
Java 中的 Object.clone()
: 1 2 ArrayList<String> list = new ArrayList <>(Arrays.asList("a" , "b" )); ArrayList<String> cloned = (ArrayList<String>) list.clone();
总结
原型模式 通过克隆原型创建对象,提高效率和灵活性。
Java 实现 依赖 Cloneable
和
clone()
,可实现浅拷贝或深拷贝。
Mermaid UML 展示了原型模式的核心结构。
结构型模式(Structural
Patterns)
适配器(Adapter)
适配器模式(Adapter
Pattern)是一种结构型设计模式,用于将一个类的接口转换为客户端期望的另一个接口。它解决接口不兼容的问题,使原本不匹配的类能够协同工作。适配器模式有两种形式:类适配器 (通过继承)和对象适配器 (通过组合)。
以下是用 Java 实现适配器模式的讲解,并直接用 Mermaid 绘制 UML
类图。
1. 适配器模式的定义
核心思想 :通过一个适配器,将不兼容的接口转换为目标接口。
目的 :
让现有类适配新接口,无需修改原有代码。
提高代码复用性。
适用场景 :
集成遗留系统或第三方库。
接口不匹配但功能类似的情况。
2. 适配器模式的结构
目标接口(Target) :客户端期望的接口。
适配者(Adaptee) :需要适配的现有类,接口不兼容。
适配器(Adapter) :实现目标接口,调用适配者的方法。
UML 图
对象适配器版本:
classDiagram
class Target {
+request()
}
class Adaptee {
+specificRequest()
}
class Adapter {
-adaptee: Adaptee
+request()
}
Adapter ..|> Target : implements
Adapter --> Adaptee : uses
类适配器版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 classDiagram class Target { +request() } class Adaptee { +specificRequest() } class Adapter { +request() } Target <|.. Adapter : implements Adaptee <|-- Adapter : extends
说明
Target
:目标接口,定义客户端期望的方法。
Adaptee
:适配者,提供不兼容的功能。
Adapter
:
对象适配器:通过组合(-->
)持有
Adaptee
。
类适配器:通过继承(<|--
)扩展
Adaptee
。
关系 :
Target <|.. Adapter
:适配器实现目标接口。
对象适配器:Adapter --> Adaptee
(组合)。
类适配器:Adaptee <|-- Adapter
(继承)。
3. Java 实现示例
以下是一个将旧电源接口适配为新接口的例子。
3.1 目标接口
1 2 3 4 public interface NewPower { void providePower () ; }
3.2 适配者类
1 2 3 4 5 6 public class OldPower { public void outputPower () { System.out.println("Outputting power from old system" ); } }
3.3 对象适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 public class PowerAdapter implements NewPower { private OldPower oldPower; public PowerAdapter (OldPower oldPower) { this .oldPower = oldPower; } @Override public void providePower () { oldPower.outputPower(); } }
3.4 类适配器(替代实现)
1 2 3 4 5 6 7 public class PowerAdapterClass extends OldPower implements NewPower { @Override public void providePower () { outputPower(); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 public class Main { public static void main (String[] args) { OldPower oldPower = new OldPower (); NewPower adapter = new PowerAdapter (oldPower); adapter.providePower(); NewPower adapterClass = new PowerAdapterClass (); adapterClass.providePower(); } }
4. 工作原理
对象适配器 :通过组合持有适配者对象,转换调用。
类适配器 :通过继承适配者并实现目标接口,转换调用。
5. 优点
复用性 :无需修改现有代码即可复用适配者。
灵活性 :对象适配器通过组合更灵活,类适配器适合简单场景。
解耦 :客户端只依赖目标接口。
6. 缺点
复杂度 :增加一个适配器类,可能提高系统复杂性。
类适配器局限 :Java
单继承限制了类适配器的使用。
7. 与其他模式的对比
目的
接口转换
增强功能
结构
适配已有类
包装同类对象
关系
转换调用
递归调用
8. 实际应用场景
IO 流 :InputStreamReader
适配
InputStream
到 Reader
。
事件监听 :MouseAdapter
适配
MouseListener
接口。
第三方库 :适配旧 API 到新系统。
9. 源码中的例子
Java 中的 InputStreamReader
: 1 2 InputStream input = new FileInputStream ("file.txt" );Reader reader = new InputStreamReader (input);
总结
适配器模式 通过转换接口实现兼容性,支持对象适配器(组合)和类适配器(继承)。
Java 实现 依赖接口和组合/继承机制。
Mermaid UML 展示了两种形式的结构。
如果需要深究某种适配器或调整 UML 图,请告诉我!
桥接(Bridge)
桥接模式(Bridge
Pattern)是一种结构型设计模式,用于将抽象部分与实现部分分离,使它们可以独立变化。它通过组合而非继承,将两个维度的变化解耦,增强系统的灵活性和扩展性。
以下是用 Java 实现桥接模式的详细讲解,并在“模式结构”部分提供 Mermaid
UML 图。
1. 桥接模式的定义
核心思想 :将抽象(Abstraction)与实现(Implementation)分离,通过组合关系连接两者。
目的 :
解耦抽象和实现,避免多层继承导致的复杂性。
支持独立扩展抽象和实现。
适用场景 :
一个类存在两个独立变化的维度(如形状和颜色)。
需要在运行时动态切换实现。
避免继承带来的紧耦合。
2. 桥接模式的结构
抽象部分(Abstraction) :定义高层接口,包含对实现的引用。
修正抽象(Refined
Abstraction) :扩展抽象部分,提供具体功能。
实现接口(Implementor) :定义实现部分的接口。
具体实现(Concrete
Implementor) :实现接口的具体类。
Mermaid UML 图
classDiagram
class Abstraction {
-implementor: Implementor
+operation()
}
class RefinedAbstraction {
+operation()
}
class Implementor {
+operationImpl()
}
class ConcreteImplementorA {
+operationImpl()
}
class ConcreteImplementorB {
+operationImpl()
}
RefinedAbstraction --|> Abstraction : extends
ConcreteImplementorA ..|> Implementor : implements
ConcreteImplementorB ..|> Implementor : implements
Abstraction --> Implementor : uses
3. Java 实现示例
以下是一个绘制形状(矩形)并支持不同绘制方式(颜色)的桥接模式示例。
3.1 实现接口
1 2 3 4 public interface DrawAPI { void drawRectangle (int width, int height) ; }
3.2 具体实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class RedDraw implements DrawAPI { @Override public void drawRectangle (int width, int height) { System.out.println("Drawing a red rectangle: " + width + "x" + height); } } public class BlueDraw implements DrawAPI { @Override public void drawRectangle (int width, int height) { System.out.println("Drawing a blue rectangle: " + width + "x" + height); } }
3.3 抽象部分
1 2 3 4 5 6 7 8 9 10 public abstract class Shape { protected DrawAPI drawAPI; protected Shape (DrawAPI drawAPI) { this .drawAPI = drawAPI; } public abstract void draw () ; }
3.4 修正抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Rectangle extends Shape { private int width; private int height; public Rectangle (int width, int height, DrawAPI drawAPI) { super (drawAPI); this .width = width; this .height = height; } @Override public void draw () { drawAPI.drawRectangle(width, height); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 public class Main { public static void main (String[] args) { Shape redRectangle = new Rectangle (10 , 5 , new RedDraw ()); redRectangle.draw(); Shape blueRectangle = new Rectangle (20 , 10 , new BlueDraw ()); blueRectangle.draw(); } }
4. 工作原理
客户端 创建具体实现(RedDraw
或
BlueDraw
)。
将实现注入抽象类(Rectangle
),通过组合连接。
调用抽象类的操作(draw()
),间接调用实现的方法。
5. 优点
解耦 :抽象和实现独立变化,互不影响。
扩展性 :可独立增加新的抽象或实现类。
运行时切换 :通过组合动态改变实现。
6. 缺点
复杂度增加 :引入额外接口和类,设计更复杂。
适用性有限 :仅适合有两个独立变化维度的场景。
7. 与适配器模式的对比
目的
分离抽象和实现
接口转换
时机
设计时规划
集成已有代码
关系
组合为主
组合或继承
8. 实际应用场景
JDBC :Driver
和
Connection
分离,驱动实现独立变化。
GUI 框架 :组件(如按钮)与绘制方式(如 Windows/Mac
风格)分离。
日志系统 :日志级别与输出方式(如文件、控制台)解耦。
9. 源码中的例子
Java 中的 java.sql.DriverManager
: 1 Connection conn = DriverManager.getConnection(url);
10. 总结
桥接模式 通过组合将抽象与实现分离,支持独立扩展。
Java 实现 依赖接口和组合,灵活性高。
UML 图 清晰展示了两部分的解耦关系。
如果需要更复杂示例(如多实现)或调整 UML,请告诉我!
组合(Composite)
组合模式(Composite
Pattern)是一种结构型设计模式,用于将对象组织成树形结构,以表示“部分-整体”的层次关系。它允许客户端统一对待单个对象(叶子)和对象集合(容器),简化操作。
以下是用 Java
实现组合模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 组合模式的定义
核心思想 :将对象组合成树形结构,使单个对象和组合对象具有一致的接口。
目的 :
统一处理叶子节点和容器节点。
隐藏内部结构差异,简化客户端代码。
适用场景 :
表示树形结构(如文件系统、组织架构)。
需要统一操作单个对象和对象集合。
2. 组合模式的结构
抽象组件(Component) :定义叶子和容器的公共接口。
叶子(Leaf) :实现组件接口,表示树中的单个对象。
容器(Composite) :实现组件接口,包含子组件集合,可递归操作。
Mermaid UML 图
classDiagram
class Component {
+operation()
+add(Component)
+remove(Component)
+getChild(int) Component
}
class Leaf {
+operation()
}
class Composite {
-children: List<Component>
+operation()
+add(Component)
+remove(Component)
+getChild(int) Component
}
Leaf ..|> Component : implements
Composite ..|> Component : implements
Composite o--> "many" Component : contains
3. Java 实现示例
以下是一个文件系统(文件和文件夹)的组合模式示例。
3.1 抽象组件
1 2 3 4 public interface FileSystemItem { void display () ; }
3.2 叶子类
1 2 3 4 5 6 7 8 9 10 11 12 13 public class File implements FileSystemItem { private String name; public File (String name) { this .name = name; } @Override public void display () { System.out.println("File: " + name); } }
3.3 容器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Folder implements FileSystemItem { private String name; private List<FileSystemItem> children; public Folder (String name) { this .name = name; this .children = new ArrayList <>(); } public void add (FileSystemItem item) { children.add(item); } public void remove (FileSystemItem item) { children.remove(item); } @Override public void display () { System.out.println("Folder: " + name); for (FileSystemItem item : children) { item.display(); } } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Main { public static void main (String[] args) { FileSystemItem file1 = new File ("doc1.txt" ); FileSystemItem file2 = new File ("doc2.txt" ); Folder folder1 = new Folder ("Documents" ); folder1.add(file1); folder1.add(file2); Folder root = new Folder ("Root" ); root.add(folder1); root.add(new File ("readme.txt" )); root.display(); } }
4. 工作原理
客户端 创建叶子(File
)和容器(Folder
)。
将叶子和子容器添加到容器中,形成树形结构。
调用统一接口(display()
),递归处理整个结构。
5. 优点
统一性 :客户端无需区分叶子和容器,使用一致接口。
扩展性 :易于添加新组件(叶子或容器)。
简化操作 :递归处理树形结构。
6. 缺点
限制性 :叶子和容器的接口必须一致,可能导致叶子实现无意义的方法(如
add
)。
复杂度 :管理树形结构可能增加系统复杂性。
7. 与装饰者模式的对比
目的
表示部分-整体关系
动态增强功能
结构
树形层次
线性包装
操作
统一处理
递归调用
8. 实际应用场景
文件系统 :文件和文件夹的树形结构。
GUI 组件 :如 Swing 中的 Container
和
Component
。
组织架构 :公司部门和员工的层次关系。
9. 源码中的例子
Java 中的 java.awt.Component
和 Container
:
1 2 Container panel = new JPanel ();panel.add(new JButton ("Click" ));
10. 总结
组合模式 通过统一接口处理树形结构,适合部分-整体场景。
Java 实现 依赖接口和递归,容器管理子组件。
UML 图 展示了组件、叶子和容器的关系。
装饰者(Decorator)
装饰者模式是一种结构型设计模式,用于动态地为对象添加功能,而无需修改其原有代码。它通过包装对象实现功能的扩展,遵循“开闭原则”(对扩展开放,对修改关闭)。
以下是用 Java
实现装饰者模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 装饰者模式的定义
核心思想 :通过组合动态地为对象添加职责,替代继承。
目的 :
增强对象功能,同时保持接口一致。
提供灵活的替代继承的扩展方式。
适用场景 :
需要动态添加功能(如日志、权限)。
无法通过子类扩展现有类。
需要多种功能组合。
2. 装饰者模式的结构
抽象组件(Component) :定义被装饰对象的接口。
具体组件(Concrete
Component) :实现组件接口,是被装饰的核心对象。
抽象装饰者(Decorator) :实现组件接口,持有组件引用,定义装饰框架。
具体装饰者(Concrete
Decorator) :扩展装饰者,添加具体功能。
Mermaid UML 图
classDiagram
class Component {
+operation()
}
class ConcreteComponent {
+operation()
}
class Decorator {
-component: Component
+operation()
}
class ConcreteDecorator {
+operation()
+addedBehavior()
}
ConcreteComponent ..|> Component : implements
Decorator ..|> Component : implements
ConcreteDecorator --|> Decorator : extends
Decorator o--> Component : contains
3. Java 实现示例
以下是一个咖啡定价的装饰者模式示例,支持添加配料(如牛奶、糖)。
3.1 抽象组件
1 2 3 4 5 public interface Coffee { double cost () ; String description () ; }
3.2 具体组件
1 2 3 4 5 6 7 8 9 10 11 12 public class SimpleCoffee implements Coffee { @Override public double cost () { return 5.0 ; } @Override public String description () { return "Simple Coffee" ; } }
3.3 抽象装饰者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class CoffeeDecorator implements Coffee { protected Coffee coffee; public CoffeeDecorator (Coffee coffee) { this .coffee = coffee; } @Override public double cost () { return coffee.cost(); } @Override public String description () { return coffee.description(); } }
3.4 具体装饰者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class MilkDecorator extends CoffeeDecorator { public MilkDecorator (Coffee coffee) { super (coffee); } @Override public double cost () { return super .cost() + 2.0 ; } @Override public String description () { return super .description() + ", Milk" ; } } public class SugarDecorator extends CoffeeDecorator { public SugarDecorator (Coffee coffee) { super (coffee); } @Override public double cost () { return super .cost() + 1.0 ; } @Override public String description () { return super .description() + ", Sugar" ; } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { public static void main (String[] args) { Coffee coffee = new SimpleCoffee (); System.out.println(coffee.description() + " $" + coffee.cost()); coffee = new MilkDecorator (coffee); System.out.println(coffee.description() + " $" + coffee.cost()); coffee = new SugarDecorator (coffee); System.out.println(coffee.description() + " $" + coffee.cost()); } }
4. 工作原理
客户端 创建具体组件(如
SimpleCoffee
)。
使用装饰者(如
MilkDecorator
、SugarDecorator
)包装组件,动态添加功能。
调用统一接口(cost()
、description()
),递归执行装饰逻辑。
5. 优点
灵活性 :动态添加或移除功能,无需修改原有类。
复用性 :装饰者可组合使用,生成多种组合。
符合开闭原则 :扩展功能不改动源代码。
6. 缺点
复杂度增加 :多层装饰导致对象层次复杂,调试困难。
类数量增多 :每个新功能需定义新装饰者。
7. 与适配器模式的对比
目的
增强功能
接口转换
结构
包装同类对象
适配不同类
调用
递归调用
转换调用
8. 实际应用场景
IO 流 :BufferedInputStream
装饰
InputStream
。
GUI 组件 :添加边框、滚动条等装饰。
日志系统 :为日志添加时间戳、格式化。
9. 源码中的例子
Java 中的 java.io
包: 1 2 InputStream input = new FileInputStream ("file.txt" );InputStream buffered = new BufferedInputStream (input);
10. 总结
装饰者模式 通过包装动态增强对象功能,保持接口一致。
Java 实现 依赖接口和组合,支持多层装饰。
UML 图 展示了组件和装饰者的递归关系。
外观(Facade)
外观模式是一种结构型设计模式,它为复杂的子系统提供一个简化的统一接口,隐藏子系统的复杂性,使客户端更容易使用。
以下是用 Java
实现外观模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 外观模式的定义
核心思想 :通过一个外观类封装子系统的复杂操作,提供简单的高层接口。
目的 :
简化客户端与子系统的交互。
解耦客户端与子系统,降低依赖性。
适用场景 :
子系统复杂且难以直接使用。
需要为子系统提供统一入口。
分层设计中隔离层间耦合。
2. 外观模式的结构
子系统(Subsystem) :一组独立的类,完成特定功能。
外观(Facade) :封装子系统,提供简化的接口。
客户端(Client) :通过外观访问子系统。
Mermaid UML 图
classDiagram
class Facade {
-subsystemA: SubsystemA
-subsystemB: SubsystemB
+operation()
}
class SubsystemA {
+operationA()
}
class SubsystemB {
+operationB()
}
class Client
Client --> Facade : uses
Facade --> SubsystemA : delegates
Facade --> SubsystemB : delegates
3. Java 实现示例
以下是一个家庭影院系统的外观模式示例,简化音响、投影仪和灯光的操作。
3.1 子系统类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class AudioSystem { public void turnOn () { System.out.println("Audio system is on" ); } public void setVolume (int level) { System.out.println("Audio volume set to " + level); } public void turnOff () { System.out.println("Audio system is off" ); } } public class Projector { public void turnOn () { System.out.println("Projector is on" ); } public void setInput (String input) { System.out.println("Projector input set to " + input); } public void turnOff () { System.out.println("Projector is off" ); } } public class Lights { public void dim (int level) { System.out.println("Lights dimmed to " + level + "%" ); } public void turnOff () { System.out.println("Lights are off" ); } }
3.2 外观类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class HomeTheaterFacade { private AudioSystem audio; private Projector projector; private Lights lights; public HomeTheaterFacade (AudioSystem audio, Projector projector, Lights lights) { this .audio = audio; this .projector = projector; this .lights = lights; } public void watchMovie (String input) { System.out.println("Preparing to watch a movie..." ); audio.turnOn(); audio.setVolume(50 ); projector.turnOn(); projector.setInput(input); lights.dim(20 ); System.out.println("Movie is ready!" ); } public void endMovie () { System.out.println("Shutting down the movie..." ); audio.turnOff(); projector.turnOff(); lights.turnOff(); } }
3.3 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Main { public static void main (String[] args) { AudioSystem audio = new AudioSystem (); Projector projector = new Projector (); Lights lights = new Lights (); HomeTheaterFacade theater = new HomeTheaterFacade (audio, projector, lights); theater.watchMovie("HDMI" ); theater.endMovie(); } }
4. 工作原理
客户端 创建子系统实例并注入外观类。
调用外观的简化方法(如
watchMovie
),外观协调子系统完成任务。
子系统独立运行,客户端无需直接操作。
5. 优点
简化接口 :降低客户端使用子系统的复杂度。
解耦 :客户端与子系统隔离,降低耦合度。
封装性 :隐藏子系统细节。
6. 缺点
功能有限 :外观可能无法满足所有需求,客户端可能仍需直接访问子系统。
新增开销 :增加一个外观类,可能提高维护成本。
7. 与适配器模式的对比
目的
简化接口
接口转换
作用对象
整个子系统
单个类
复杂度
降低使用复杂度
增加适配层复杂度
8. 实际应用场景
数据库访问 :封装 JDBC 操作,提供简单 API。
多媒体系统 :简化设备控制(如电视、音响)。
工具库 :为复杂底层功能提供高层接口。
9. 源码中的例子
Java 中的 java.util.logging.Logger
: 1 2 Logger logger = Logger.getLogger("myLogger" ); logger.info("Message" );
10. 总结
外观模式 通过封装子系统提供简化的统一接口,降低使用难度。
Java 实现 依赖组合,协调多个子系统。
UML 图 展示了外观与子系统的委托关系。
享元(Flyweight)
享元模式(Flyweight
Pattern)是一种结构型设计模式,旨在通过共享对象来减少内存使用和提高性能。它适用于系统中存在大量相似对象的情况,通过复用已有的对象而不是创建新实例来优化资源消耗。
以下是用 Java
实现享元模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 享元模式的定义
核心思想 :共享相同的对象实例,减少重复创建,降低内存开销。
目的 :
提高系统效率,特别是在对象数量庞大时。
分离对象的内在状态(共享)和外在状态(不共享)。
适用场景 :
系统有大量相似对象。
对象创建成本高且可共享。
需要缓存不可变对象。
2. 享元模式的结构
抽象享元(Flyweight) :定义共享对象的接口。
具体享元(Concrete
Flyweight) :实现享元接口,存储内在状态。
享元工厂(Flyweight
Factory) :管理享元对象的创建和共享。
客户端(Client) :使用享元对象,维护外在状态。
Mermaid UML 图
classDiagram
class Flyweight {
+operation(extrinsicState)
}
class ConcreteFlyweight {
-intrinsicState
+operation(extrinsicState)
}
class FlyweightFactory {
-flyweights: Map
+getFlyweight(key) Flyweight
}
class Client
ConcreteFlyweight ..|> Flyweight : implements
FlyweightFactory --> Flyweight : creates
Client --> FlyweightFactory : uses
Client --> Flyweight : uses
3. Java 实现示例
以下是一个绘制圆形的享元模式示例,共享颜色相同的圆形对象。
3.1 抽象享元接口
1 2 3 4 public interface Shape { void draw (int x, int y) ; }
3.2 具体享元类
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Circle implements Shape { private String color; public Circle (String color) { this .color = color; } @Override public void draw (int x, int y) { System.out.println("Drawing a " + color + " circle at (" + x + ", " + y + ")" ); } }
3.3 享元工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ShapeFactory { private static final Map<String, Shape> circleMap = new HashMap <>(); public static Shape getCircle (String color) { Shape circle = circleMap.get(color); if (circle == null ) { circle = new Circle (color); circleMap.put(color, circle); System.out.println("Created a new " + color + " circle" ); } return circle; } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 public class Main { private static final String[] colors = {"Red" , "Blue" , "Green" }; public static void main (String[] args) { for (int i = 0 ; i < 10 ; i++) { String color = colors[(int ) (Math.random() * colors.length)]; Shape circle = ShapeFactory.getCircle(color); circle.draw(i, i * 2 ); } } }
输出示例 : 1 2 3 4 5 6 7 8 9 Created a new Red circle Drawing a Red circle at (0, 0) Created a new Blue circle Drawing a Blue circle at (1, 2) Drawing a Red circle at (2, 4) Created a new Green circle Drawing a Green circle at (3, 6) Drawing a Blue circle at (4, 8) ...
-
说明 :相同颜色的圆形只创建一次,之后共享。
4. 工作原理
客户端 通过工厂请求享元对象(如
getCircle
)。
工厂检查是否已有对应对象,若无则创建并缓存,若有则返回共享实例。
客户端传入外在状态(如位置),调用享元方法。
5. 内在状态 vs 外在状态
内在状态 :存储在享元对象中,不可变且可共享(如
color
)。
外在状态 :由客户端维护,不共享(如
x
、y
坐标)。
6. 优点
节省内存 :共享对象减少实例数量。
性能提升 :避免重复创建耗时对象。
集中管理 :工厂统一管理共享对象。
7. 缺点
复杂度增加 :需要分离内外状态,设计更复杂。
线程安全 :共享对象需考虑并发访问(可用同步或不可变设计)。
适用性有限 :仅适合大量相似对象的场景。
8. 与单例模式的对比
实例数量
多实例(按键共享)
单实例
目的
共享减少内存
确保唯一性
管理
工厂管理
静态方法控制
9. 实际应用场景
字符缓存 :文本编辑器中共享字体或字符对象。
游戏开发 :复用纹理或模型实例。
连接池 :数据库连接或线程池的共享管理。
10. 源码中的例子
Java 中的 Integer.valueOf()
: 1 2 3 Integer a = Integer.valueOf(100 ); Integer b = Integer.valueOf(100 );System.out.println(a == b);
11. 总结
享元模式 通过共享对象优化资源使用,分离内外状态。
Java 实现 依赖工厂和缓存(如
Map
),支持高效复用。
UML 图 展示了享元、工厂和客户端的关系。
代理(Proxy)
代理模式(Proxy
Pattern)是一种结构型设计模式,通过引入一个代理对象来控制对目标对象的访问。它可以在不修改目标对象的情况下,增强功能(如权限检查、延迟加载、日志记录等)。代理模式的核心是为目标对象提供一个替代者,客户端通过代理间接访问目标。
以下是用 Java
实现代理模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 代理模式的定义
核心思想 :通过代理对象控制对目标对象的访问,增加额外的功能或限制。
目的 :
适用场景 :
延迟加载(虚拟代理)。
访问控制(保护代理)。
日志或缓存(装饰代理)。
2. 代理模式的结构
抽象主题(Subject) :定义目标和代理的公共接口。
真实主题(Real
Subject) :实现主题接口,是被代理的目标对象。
代理(Proxy) :实现主题接口,持有真实主题引用,控制访问并添加功能。
Mermaid UML 图
classDiagram
class Subject {
+request()
}
class RealSubject {
+request()
}
class Proxy {
-realSubject: RealSubject
+request()
}
RealSubject ..|> Subject : implements
Proxy ..|> Subject : implements
Proxy --> RealSubject : uses
3. 代理模式的类型
静态代理 :代理类在编译时手动创建。
动态代理 :运行时通过反射动态生成(如 Java 的
Proxy
类)。
虚拟代理 :延迟加载目标对象。
保护代理 :控制访问权限。
4. Java 实现示例
以下是一个文件访问的代理模式示例,展示静态代理和动态代理。
4.1 抽象主题
1 2 3 4 public interface FileService { void readFile (String fileName) ; }
4.2 真实主题
1 2 3 4 5 6 7 public class FileServiceImpl implements FileService { @Override public void readFile (String fileName) { System.out.println("Reading file: " + fileName); } }
4.3 静态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class FileServiceProxy implements FileService { private FileService realService; public FileServiceProxy (FileService realService) { this .realService = realService; } @Override public void readFile (String fileName) { System.out.println("Logging: Attempting to read file " + fileName); realService.readFile(fileName); System.out.println("Logging: File read completed" ); } }
4.4 动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class DynamicProxyHandler implements InvocationHandler { private Object target; public DynamicProxyHandler (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Dynamic Logging: Before " + method.getName()); Object result = method.invoke(target, args); System.out.println("Dynamic Logging: After " + method.getName()); return result; } public static FileService createProxy (FileService target) { return (FileService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DynamicProxyHandler (target) ); } }
4.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Main { public static void main (String[] args) { FileService realService = new FileServiceImpl (); FileService staticProxy = new FileServiceProxy (realService); staticProxy.readFile("data.txt" ); FileService dynamicProxy = DynamicProxyHandler.createProxy(realService); dynamicProxy.readFile("config.txt" ); } }
5. 工作原理
客户端 通过代理对象调用方法。
代理执行额外逻辑(如日志、权限检查),然后委托给真实主题。
真实主题完成核心操作,返回结果。
6. 优点
功能增强 :无需修改目标代码即可添加功能。
控制访问 :代理可限制或延迟对目标的访问。
灵活性 :动态代理支持运行时调整。
7. 缺点
性能开销 :代理层增加调用
overhead,尤其是动态代理。
复杂度 :实现动态代理需熟悉反射。
静态局限 :静态代理需为每个目标手动编写代理类。
8. 与装饰者模式的对比
目的
控制访问
增强功能
关注点
代理行为
对象功能
结构
单层代理
多层包装
9. 实际应用场景
延迟加载 :如 ORM 框架中的懒加载(Hibernate)。
权限控制 :限制对敏感资源的访问。
AOP :Spring
中通过代理实现切面(如日志、事务)。
10. 源码中的例子
Java 中的 java.lang.reflect.Proxy
: 1 2 3 4 5 6 7 8 9 Runnable proxy = (Runnable) Proxy.newProxyInstance( Runnable.class.getClassLoader(), new Class <?>[]{Runnable.class}, (p, method, args) -> { System.out.println("Before run" ); return null ; } ); proxy.run();
11. 总结
代理模式 通过代理对象控制目标访问,支持静态和动态实现。
Java 实现 静态代理用组合,动态代理用反射。
UML 图 展示了代理与真实主题的关系。
行为型模式(Behavioral
Patterns)
责任链(Chain of
Responsibility)
我假设你指的是“责任链模式”(Chain of Responsibility
Pattern),可能是“责任链”中的简写或输入问题。责任链模式是一种行为型设计模式,它将请求的处理者组织成一个链,请求沿着链传递,直到某个处理者处理它或链结束。这种模式解耦了请求的发送者和接收者,增强了灵活性。
以下是用 Java
实现责任链模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 责任链模式的定义
核心思想 :将请求的处理者组成一个链,请求沿链传递,每个处理者决定处理或转发。
目的 :
解耦请求发送者和处理者。
动态调整处理顺序或责任分配。
适用场景 :
请求有多个处理者,但处理者不确定。
需要动态指定处理流程。
处理逻辑分层或条件化。
2. 责任链模式的结构
抽象处理者(Handler) :定义处理请求的接口和链的链接方法。
具体处理者(Concrete
Handler) :实现处理逻辑,决定处理或传递请求。
客户端(Client) :发起请求并交给链的起点。
Mermaid UML 图
classDiagram
class Handler {
-next: Handler
+setNext(Handler)
+handleRequest(request)
}
class ConcreteHandlerA {
+handleRequest(request)
}
class ConcreteHandlerB {
+handleRequest(request)
}
class Client
ConcreteHandlerA ..|> Handler : implements
ConcreteHandlerB ..|> Handler : implements
Handler o--> Handler : next
Client --> Handler : sends to
3. Java 实现示例
以下是一个日志处理的责任链模式示例,根据日志级别分发处理。
3.1 抽象处理者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public abstract class Logger { protected Logger nextLogger; protected int level; public void setNext (Logger nextLogger) { this .nextLogger = nextLogger; } public void logMessage (int level, String message) { if (this .level <= level) { write(message); } if (nextLogger != null ) { nextLogger.logMessage(level, message); } } protected abstract void write (String message) ; }
3.2 具体处理者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class ConsoleLogger extends Logger { public ConsoleLogger (int level) { this .level = level; } @Override protected void write (String message) { System.out.println("Console Logger: " + message); } } public class FileLogger extends Logger { public FileLogger (int level) { this .level = level; } @Override protected void write (String message) { System.out.println("File Logger: " + message); } } public class ErrorLogger extends Logger { public ErrorLogger (int level) { this .level = level; } @Override protected void write (String message) { System.out.println("Error Logger: " + message); } }
3.3 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Main { public static final int INFO = 1 ; public static final int DEBUG = 2 ; public static final int ERROR = 3 ; public static void main (String[] args) { Logger consoleLogger = new ConsoleLogger (INFO); Logger fileLogger = new FileLogger (DEBUG); Logger errorLogger = new ErrorLogger (ERROR); consoleLogger.setNext(fileLogger); fileLogger.setNext(errorLogger); consoleLogger.logMessage(INFO, "This is an info message" ); consoleLogger.logMessage(DEBUG, "This is a debug message" ); consoleLogger.logMessage(ERROR, "This is an error message" ); } }
输出 : 1 2 3 4 5 6 Console Logger: This is an info message Console Logger: This is a debug message File Logger: This is a debug message Console Logger: This is an error message File Logger: This is an error message Error Logger: This is an error message
-
说明 :消息按级别沿链传递,符合条件的处理者输出日志。
4. 工作原理
客户端 构建责任链,设置处理者顺序。
请求从链头开始传递,每个处理者检查是否处理。
若当前处理者不处理,则传递给下一个,直到链结束。
5. 优点
解耦 :请求发送者无需知道具体处理者。
灵活性 :可动态调整链的结构和顺序。
扩展性 :易于添加新处理者。
6. 缺点
不确定性 :请求可能未被处理(链尾无匹配)。
性能开销 :链过长可能影响效率。
调试复杂 :多处理者时难以跟踪流程。
7. 与装饰者模式的对比
目的
分担责任
增强功能
传递
条件传递
递归调用
结果
单处理或无处理
层层增强
8. 实际应用场景
Servlet 过滤器 :请求沿 Filter 链处理。
日志框架 :如 SLF4J 的日志级别处理。
事件处理 :GUI 事件传递。
9. 源码中的例子
Java 中的 javax.servlet.FilterChain
: 1 2 3 4 5 6 7 8 public class MyFilter implements Filter { @Override public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) { System.out.println("Before filter" ); chain.doFilter(request, response); System.out.println("After filter" ); } }
10. 总结
责任链模式 通过链式结构分担请求处理,解耦发送者和接收者。
Java 实现 依赖抽象类和链式引用,支持动态调整。
UML 图 展示了处理者的链接关系。
命令(Command)
命令模式(Command
Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而允许参数化客户端、记录请求日志、支持撤销操作以及将请求排队或延迟执行。命令模式通过解耦请求的发送者和接收者,增强了系统的灵活性。
以下是用 Java
实现命令模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 命令模式的定义
核心思想 :将请求封装为命令对象,分离请求的发起者(Invoker)和执行者(Receiver)。
目的 :
解耦调用者和执行逻辑。
支持请求的存储、撤销、重做等操作。
适用场景 :
需要参数化操作(如菜单、按钮)。
支持事务或回滚。
请求需要排队或延迟执行。
2. 命令模式的结构
抽象命令(Command) :定义命令的接口,通常包含执行方法。
具体命令(Concrete
Command) :实现命令接口,关联接收者并调用其操作。
接收者(Receiver) :执行具体操作的类。
调用者(Invoker) :持有命令对象并触发执行。
客户端(Client) :创建命令并配置调用者。
Mermaid UML 图
classDiagram
class Command {
+execute()
}
class ConcreteCommand {
-receiver: Receiver
+execute()
}
class Receiver {
+action()
}
class Invoker {
-command: Command
+setCommand(Command)
+executeCommand()
}
class Client
ConcreteCommand ..|> Command : implements
ConcreteCommand --> Receiver : uses
Invoker --> Command : holds
Client --> Invoker : configures
Client --> ConcreteCommand : creates
3. Java 实现示例
以下是一个控制灯光开关的命令模式示例。
3.1 接收者
1 2 3 4 5 6 7 8 9 10 public class Light { public void turnOn () { System.out.println("Light is ON" ); } public void turnOff () { System.out.println("Light is OFF" ); } }
3.2 抽象命令
1 2 3 4 public interface Command { void execute () ; }
3.3 具体命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class LightOnCommand implements Command { private Light light; public LightOnCommand (Light light) { this .light = light; } @Override public void execute () { light.turnOn(); } } public class LightOffCommand implements Command { private Light light; public LightOffCommand (Light light) { this .light = light; } @Override public void execute () { light.turnOff(); } }
3.4 调用者
1 2 3 4 5 6 7 8 9 10 11 12 public class RemoteControl { private Command command; public void setCommand (Command command) { this .command = command; } public void pressButton () { command.execute(); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Main { public static void main (String[] args) { Light light = new Light (); Command lightOn = new LightOnCommand (light); Command lightOff = new LightOffCommand (light); RemoteControl remote = new RemoteControl (); remote.setCommand(lightOn); remote.pressButton(); remote.setCommand(lightOff); remote.pressButton(); } }
4. 工作原理
客户端 创建接收者和命令,将命令与接收者关联。
将命令注入调用者(RemoteControl
)。
调用者触发命令执行,命令调用接收者的方法。
5. 优点
解耦 :请求发起者和执行者分离。
扩展性 :易于添加新命令。
支持撤销 :可通过添加 undo()
方法实现回滚。
可记录 :命令对象可存储用于日志或重做。
6. 缺点
类数量增加 :每个操作需定义新命令类。
复杂度 :简单场景可能显得过于繁琐。
7. 支持撤销的扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public interface Command { void execute () ; void undo () ; } public class LightOnCommand implements Command { private Light light; public LightOnCommand (Light light) { this .light = light; } @Override public void execute () { light.turnOn(); } @Override public void undo () { light.turnOff(); } } public class Main { public static void main (String[] args) { Light light = new Light (); Command lightOn = new LightOnCommand (light); RemoteControl remote = new RemoteControl (); remote.setCommand(lightOn); remote.pressButton(); ((LightOnCommand) lightOn).undo(); } }
8. 与策略模式的对比
目的
封装请求
封装算法
关注点
操作执行
行为选择
结构
命令+接收者
上下文+策略
9. 实际应用场景
GUI 按钮 :按钮点击触发命令。
事务管理 :支持回滚的操作队列。
宏命令 :组合多个命令执行。
10. 源码中的例子
Java 中的 Runnable
: 1 2 Thread thread = new Thread (() -> System.out.println("Running" ));thread.start();
11. 总结
命令模式 将请求封装为对象,解耦发起者和执行者。
Java 实现 依赖接口和组合,支持扩展功能如撤销。
UML 图 展示了命令、接收者和调用者的关系。
如果需要宏命令示例(组合多个命令)或调整 UML,请告诉我!
解释器(Interpreter)
解释器模式(Interpreter
Pattern)是一种行为型设计模式,用于定义一种语言的语法,并通过解释器对象来解析和执行这种语言的语句。它特别适合处理简单的语法规则或领域特定语言(DSL),将复杂的表达式分解为可递归解释的对象。
以下是对解释器模式的详细讲解,包括定义、结构、Java
实现示例及其优缺点。
1. 解释器模式的定义
核心思想 :为特定语言定义语法表示,并通过递归解释器解析语句。
目的 :
将语法规则封装为对象,便于处理复杂的表达式。
支持动态解释和执行语言规则。
适用场景 :
解析简单的脚本或表达式(如数学表达式、查询语言)。
处理规则引擎或自定义语言。
2. 解释器模式的结构
抽象表达式(Abstract
Expression) :定义解释方法的接口。
终结符表达式(Terminal
Expression) :表示语法中的基本元素,直接实现解释逻辑。
非终结符表达式(Non-Terminal
Expression) :表示复合规则,递归调用子表达式解释。
上下文(Context) :存储解释过程中需要的全局信息(如变量值)。
客户端(Client) :构建表达式树并调用解释器。
Mermaid UML 图
classDiagram
class AbstractExpression {
+interpret(context) int
}
class TerminalExpression {
-value: int
+interpret(context) int
}
class NonTerminalExpression {
-left: AbstractExpression
-right: AbstractExpression
+interpret(context) int
}
class Context {
-data: Map
+getValue(key) int
+setValue(key, value)
}
class Client
TerminalExpression ..|> AbstractExpression : implements
NonTerminalExpression ..|> AbstractExpression : implements
NonTerminalExpression o--> "2" AbstractExpression : contains
Client --> AbstractExpression : uses
Client --> Context : uses
3. Java 实现示例
以下是一个解析简单加减法的解释器模式示例。
3.1 上下文类
1 2 3 4 5 6 7 8 9 10 11 12 public class Context { private Map<String, Integer> variables = new HashMap <>(); public void setVariable (String name, int value) { variables.put(name, value); } public int getVariable (String name) { return variables.getOrDefault(name, 0 ); } }
3.2 抽象表达式
1 2 3 4 public interface Expression { int interpret (Context context) ; }
3.3 终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class NumberExpression implements Expression { private String value; public NumberExpression (String value) { this .value = value; } @Override public int interpret (Context context) { try { return Integer.parseInt(value); } catch (NumberFormatException e) { return context.getVariable(value); } } }
3.4 非终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class AddExpression implements Expression { private Expression left; private Expression right; public AddExpression (Expression left, Expression right) { this .left = left; this .right = right; } @Override public int interpret (Context context) { return left.interpret(context) + right.interpret(context); } } public class SubtractExpression implements Expression { private Expression left; private Expression right; public SubtractExpression (Expression left, Expression right) { this .left = left; this .right = right; } @Override public int interpret (Context context) { return left.interpret(context) - right.interpret(context); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Main { public static void main (String[] args) { Context context = new Context (); context.setVariable("x" , 10 ); context.setVariable("y" , 5 ); Expression expression = new SubtractExpression ( new AddExpression ( new NumberExpression ("x" ), new NumberExpression ("y" ) ), new NumberExpression ("3" ) ); int result = expression.interpret(context); System.out.println("Result: " + result); } }
4. 工作原理
客户端 构建表达式树(如
x + y - 3
)。
将上下文(变量值)传递给表达式。
表达式递归调用 interpret()
方法,计算结果:
5. 优点
灵活性 :易于扩展新语法规则(新增表达式类)。
模块化 :语法规则封装为独立对象。
可解释性 :支持动态解析语言。
6. 缺点
复杂度高 :大量表达式类增加系统复杂性。
性能开销 :递归解析复杂表达式可能效率低。
适用性有限 :仅适合简单语言,复杂语法(如完整编程语言)不实用。
7. 与其他模式的对比
目的
解析语法
封装请求
结构
表达式树
命令对象
执行
递归解释
单次调用
8. 实际应用场景
数学表达式 :计算器程序解析公式。
规则引擎 :解释业务规则。
脚本语言 :简单 DSL 的解析。
9. 源码中的例子
Java 中的正则表达式(java.util.regex
):
1 2 3 4 5 Pattern pattern = Pattern.compile("\\d+" ); Matcher matcher = pattern.matcher("123" );if (matcher.matches()) { System.out.println("Valid number" ); }
10. 总结
解释器模式 通过对象表示语法规则,递归解析表达式。
Java 实现 依赖接口和表达式树,支持动态解释。
UML 图 展示了表达式和上下文的关系。
迭代器(Iterator)
迭代器模式(Iterator
Pattern)是一种行为型设计模式,它提供了一种方法来顺序访问聚合对象(如集合、列表或数组)的元素,而无需暴露其内部结构。迭代器模式将遍历逻辑从集合中分离出来,增强了封装性和灵活性。
以下是用 Java
实现迭代器模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 迭代器模式的定义
核心思想 :通过迭代器对象提供对集合元素的顺序访问,隐藏集合的实现细节。
目的 :
统一访问不同类型的集合。
分离集合的遍历逻辑和数据存储。
适用场景 :
需要遍历复杂数据结构(如树、图)。
集合类型多样但需一致访问。
增强集合的封装性。
2. 迭代器模式的结构
抽象迭代器(Iterator) :定义遍历接口,如
hasNext()
和 next()
。
具体迭代器(Concrete
Iterator) :实现迭代器接口,跟踪遍历位置。
抽象聚合(Aggregate) :定义创建迭代器的方法。
具体聚合(Concrete
Aggregate) :实现聚合接口,存储数据并返回迭代器。
客户端(Client) :使用迭代器遍历集合。
Mermaid UML 图
classDiagram
class Iterator {
+hasNext() boolean
+next() Object
}
class ConcreteIterator {
-aggregate: ConcreteAggregate
-index: int
+hasNext() boolean
+next() Object
}
class Aggregate {
+createIterator() Iterator
}
class ConcreteAggregate {
-items: List
+createIterator() Iterator
}
class Client
ConcreteIterator ..|> Iterator : implements
ConcreteAggregate ..|> Aggregate : implements
ConcreteAggregate --> ConcreteIterator : creates
ConcreteIterator --> ConcreteAggregate : references
Client --> Iterator : uses
Client --> Aggregate : uses
3. Java 实现示例
以下是一个简单列表的迭代器模式示例。
3.1 抽象迭代器
1 2 3 4 5 public interface Iterator { boolean hasNext () ; Object next () ; }
3.2 抽象聚合
1 2 3 4 public interface Collection { Iterator createIterator () ; }
3.3 具体聚合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class MyList implements Collection { private String[] items; public MyList (String[] items) { this .items = items; } @Override public Iterator createIterator () { return new ListIterator (this ); } public String get (int index) { return items[index]; } public int size () { return items.length; } }
3.4 具体迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class ListIterator implements Iterator { private MyList list; private int index; public ListIterator (MyList list) { this .list = list; this .index = 0 ; } @Override public boolean hasNext () { return index < list.size(); } @Override public Object next () { if (hasNext()) { return list.get(index++); } return null ; } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Main { public static void main (String[] args) { String[] data = {"Apple" , "Banana" , "Cherry" }; MyList list = new MyList (data); Iterator iterator = list.createIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
4. 工作原理
客户端 创建具体聚合(如
MyList
)并获取迭代器。
使用迭代器的 hasNext()
和 next()
方法顺序访问元素。
迭代器内部维护遍历状态,隐藏聚合的实现细节。
5. 优点
封装性 :隐藏集合内部结构,保护数据。
统一性 :为不同集合提供一致的遍历接口。
解耦 :分离遍历逻辑和集合实现。
6. 缺点
复杂度增加 :为简单集合引入迭代器可能显得多余。
功能有限 :标准迭代器不支持修改集合或双向遍历。
性能开销 :动态创建迭代器可能增加少量开销。
7. 与其他模式的对比
目的
顺序访问
操作复杂结构
关注点
遍历集合
扩展功能
控制权
客户端控制遍历
访问者控制操作
8. 实际应用场景
集合遍历 :Java 集合框架中的
Iterator
。
树结构 :遍历树节点。
数据库查询 :结果集迭代。
9. 源码中的例子
Java 中的 java.util.Iterator
: 1 2 3 4 5 List<String> list = Arrays.asList("A" , "B" , "C" ); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); }
10. 总结
迭代器模式 通过分离遍历逻辑提供集合的顺序访问。
Java 实现 依赖接口和具体迭代器,支持灵活遍历。
UML 图 展示了迭代器与聚合的关系。
如果需要增强版(如支持 remove()
或双向迭代器)或调整
UML,请告诉我!
中介者模式(Mediator
Pattern)是一种行为型设计模式,它通过引入一个中介者对象来封装一组对象之间的交互,从而减少对象间的直接耦合。中介者模式将多对多的通信转换为一对多的通信,提升系统的灵活性和可维护性。
以下是用 Java
实现中介者模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 中介者模式的定义
核心思想 :通过中介者协调对象间的通信,降低耦合。
目的 :
适用场景 :
对象间存在复杂的多对多关系。
需要协调多个组件的行为。
简化对象间的通信。
2. 中介者模式的结构
抽象中介者(Mediator) :定义中介者接口,声明通信方法。
具体中介者(Concrete
Mediator) :实现中介逻辑,协调同事对象。
抽象同事(Colleague) :定义同事类的接口,与中介者交互。
具体同事(Concrete
Colleague) :实现同事接口,通过中介者通信。
客户端(Client) :创建同事和中介者,发起交互。
Mermaid UML 图
classDiagram
class Mediator {
+notify(sender: Colleague, event)
}
class ConcreteMediator {
-colleagueA: ColleagueA
-colleagueB: ColleagueB
+notify(sender: Colleague, event)
}
class Colleague {
+send(event)
+receive(event)
}
class ColleagueA {
-mediator: Mediator
+send(event)
+receive(event)
}
class ColleagueB {
-mediator: Mediator
+send(event)
+receive(event)
}
ConcreteMediator ..|> Mediator : implements
ColleagueA ..|> Colleague : implements
ColleagueB ..|> Colleague : implements
ConcreteMediator --> ColleagueA : coordinates
ConcreteMediator --> ColleagueB : coordinates
ColleagueA --> Mediator : uses
ColleagueB --> Mediator : uses
3. Java 实现示例
以下是一个聊天室的中介者模式示例,用户通过中介者发送和接收消息。
3.1 抽象中介者
1 2 3 4 public interface ChatMediator { void sendMessage (String message, User sender) ; }
3.2 具体中介者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class ChatRoom implements ChatMediator { private List<User> users = new ArrayList <>(); public void addUser (User user) { users.add(user); } @Override public void sendMessage (String message, User sender) { for (User user : users) { if (user != sender) { user.receive(message); } } } }
3.3 抽象同事
1 2 3 4 5 6 7 8 9 10 11 12 13 public abstract class User { protected ChatMediator mediator; protected String name; public User (ChatMediator mediator, String name) { this .mediator = mediator; this .name = name; } public abstract void send (String message) ; public abstract void receive (String message) ; }
3.4 具体同事
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class ChatUser extends User { public ChatUser (ChatMediator mediator, String name) { super (mediator, name); } @Override public void send (String message) { System.out.println(name + " sends: " + message); mediator.sendMessage(message, this ); } @Override public void receive (String message) { System.out.println(name + " receives: " + message); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Main { public static void main (String[] args) { ChatRoom chatRoom = new ChatRoom (); User alice = new ChatUser (chatRoom, "Alice" ); User bob = new ChatUser (chatRoom, "Bob" ); User charlie = new ChatUser (chatRoom, "Charlie" ); chatRoom.addUser(alice); chatRoom.addUser(bob); chatRoom.addUser(charlie); alice.send("Hello everyone!" ); bob.send("Hi Alice!" ); } }
4. 工作原理
客户端 创建中介者和同事对象,注册同事到中介者。
同事通过中介者发送消息(send
),中介者协调分发(notify
)。
其他同事接收消息(receive
),完成通信。
5. 优点
解耦 :减少同事间的直接依赖,降低耦合。
集中控制 :交互逻辑集中在中介者,便于管理。
灵活性 :易于修改通信规则。
6. 缺点
中介者复杂性 :中介者可能变得臃肿,难以维护。
性能开销 :大量对象交互时,中介者可能成为瓶颈。
单点故障 :中介者失败影响整个系统。
7. 与观察者模式的对比
通信方式
通过中介者协调
发布-订阅
耦合
同事依赖中介者
观察者依赖主题
控制权
中介者集中控制
主题广播
8. 实际应用场景
GUI 框架 :控件间通过对话框协调。
聊天系统 :用户通过服务器通信。
航空管制 :飞机通过塔台协调。
9. 源码中的例子
Java 中的 java.util.Timer
(简化中介者):
1 2 Timer timer = new Timer ();timer.schedule(new TimerTask () { public void run () { System.out.println("Task" ); } }, 1000 );
10. 总结
中介者模式 通过中介者封装对象交互,降低耦合。
Java 实现 依赖接口和组合,支持集中管理通信。
UML 图 展示了中介者与同事的关系。
如果需要更复杂示例(如支持事件类型)或调整 UML,请告诉我!
备忘录(Memento)
备忘录模式(Memento
Pattern)是一种行为型设计模式,用于捕获并保存对象的内部状态,以便在需要时恢复到该状态,而不破坏对象的封装性。它常用于实现撤销(Undo)功能或状态快照。
以下是用 Java
实现备忘录模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 备忘录模式的定义
核心思想 :通过备忘录对象保存对象状态,并在需要时恢复。
目的 :
保存和恢复对象的状态。
保持封装性,避免暴露内部细节。
适用场景 :
需要撤销或回滚操作。
保存历史状态(如游戏存档)。
状态快照管理。
2. 备忘录模式的结构
原发器(Originator) :需要保存和恢复状态的对象,创建和使用备忘录。
备忘录(Memento) :存储原发器状态的对象,通常只提供有限访问。
管理者(Caretaker) :负责保存备忘录,但不修改其内容。
客户端(Client) :触发状态保存和恢复。
Mermaid UML 图
classDiagram
class Originator {
-state: State
+createMemento() Memento
+setMemento(Memento)
+setState(state)
+getState() State
}
class Memento {
-state: State
+getState() State
}
class Caretaker {
-memento: Memento
+setMemento(Memento)
+getMemento() Memento
}
class Client
Originator --> Memento : creates/uses
Caretaker --> Memento : holds
Client --> Originator : uses
Client --> Caretaker : uses
3. Java 实现示例
以下是一个文本编辑器的备忘录模式示例,支持保存和恢复文本状态。
3.1 备忘录类
1 2 3 4 5 6 7 8 9 10 11 12 public class Memento { private String state; public Memento (String state) { this .state = state; } public String getState () { return state; } }
3.2 原发器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class TextEditor { private String state; public void setState (String state) { this .state = state; System.out.println("Current state: " + state); } public String getState () { return state; } public Memento createMemento () { return new Memento (state); } public void setMemento (Memento memento) { this .state = memento.getState(); System.out.println("Restored state: " + state); } }
3.3 管理者类
1 2 3 4 5 6 7 8 9 10 11 12 public class History { private Memento memento; public void setMemento (Memento memento) { this .memento = memento; } public Memento getMemento () { return memento; } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { public static void main (String[] args) { TextEditor editor = new TextEditor (); History history = new History (); editor.setState("Hello" ); history.setMemento(editor.createMemento()); editor.setState("Hello World" ); editor.setMemento(history.getMemento()); } }
4. 工作原理
客户端 通过原发器(TextEditor
)设置状态。
调用 createMemento()
保存状态到备忘录,交给管理者(History
)存储。
修改状态后,通过 setMemento()
从备忘录恢复之前的状态。
5. 优点
封装性 :备忘录隐藏原发器的内部状态。
支持撤销 :方便实现回滚功能。
状态隔离 :管理者不修改备忘录内容。
6. 缺点
内存开销 :保存大量状态可能消耗内存。
复杂度 :增加备忘录和管理类,提高系统复杂性。
状态管理 :多状态时需额外设计存储结构。
7. 与命令模式的对比
目的
保存/恢复状态
封装请求
关注点
状态管理
操作执行
撤销
通过状态恢复
通过命令回滚
8. 实际应用场景
文本编辑器 :撤销和重做功能。
游戏 :保存和加载游戏进度。
数据库 :事务回滚。
9. 源码中的例子
Java 中的 java.util.Date
(简化备忘录思想):
1 2 3 Date date = new Date ();long time = date.getTime(); date.setTime(time);
10. 总结
备忘录模式 通过备忘录保存和恢复对象状态,支持撤销。
Java
实现 依赖原发器创建和使用备忘录,管理者存储。
UML 图 展示了原发器、备忘录和管理者的关系。
如果需要多状态管理示例(如历史记录列表)或调整 UML,请告诉我!
观察者(Observer)
观察者模式(Observer
Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知并更新。观察者模式也被称为“发布-订阅模式”,广泛用于事件处理和状态监控。
以下是用 Java
实现观察者模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 观察者模式的定义
核心思想 :通过主题(Subject)维护观察者(Observer)列表,当主题状态变化时通知所有观察者。
目的 :
适用场景 :
事件监听(如 GUI 按钮点击)。
数据变化通知(如股票价格)。
发布-订阅系统。
2. 观察者模式的结构
抽象主题(Subject) :维护观察者列表,提供添加、移除和通知方法。
具体主题(Concrete
Subject) :实现主题接口,存储状态并触发通知。
抽象观察者(Observer) :定义更新接口。
具体观察者(Concrete
Observer) :实现更新逻辑,响应主题变化。
客户端(Client) :创建主题和观察者,发起交互。
Mermaid UML 图
classDiagram
class Subject {
+attach(Observer)
+detach(Observer)
+notify()
}
class ConcreteSubject {
-state: State
-observers: List<Observer>
+attach(Observer)
+detach(Observer)
+notify()
+setState(state)
+getState() State
}
class Observer {
+update()
}
class ConcreteObserver {
-subject: Subject
+update()
}
ConcreteSubject ..|> Subject : implements
ConcreteObserver ..|> Observer : implements
ConcreteSubject o--> "many" Observer : notifies
ConcreteObserver --> Subject : observes
3. Java 实现示例
以下是一个天气站的观察者模式示例,天气变化时通知显示器。
3.1 抽象观察者
1 2 3 4 public interface Observer { void update (float temperature) ; }
3.2 抽象主题
1 2 3 4 5 6 public interface WeatherStation { void addObserver (Observer observer) ; void removeObserver (Observer observer) ; void notifyObservers () ; }
3.3 具体主题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class ConcreteWeatherStation implements WeatherStation { private List<Observer> observers = new ArrayList <>(); private float temperature; @Override public void addObserver (Observer observer) { observers.add(observer); } @Override public void removeObserver (Observer observer) { observers.remove(observer); } @Override public void notifyObservers () { for (Observer observer : observers) { observer.update(temperature); } } public void setTemperature (float temperature) { this .temperature = temperature; System.out.println("Temperature changed to: " + temperature); notifyObservers(); } }
3.4 具体观察者
1 2 3 4 5 6 7 8 9 10 11 12 13 public class TemperatureDisplay implements Observer { private String name; public TemperatureDisplay (String name) { this .name = name; } @Override public void update (float temperature) { System.out.println(name + " displays temperature: " + temperature); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Main { public static void main (String[] args) { ConcreteWeatherStation station = new ConcreteWeatherStation (); Observer display1 = new TemperatureDisplay ("Display 1" ); Observer display2 = new TemperatureDisplay ("Display 2" ); station.addObserver(display1); station.addObserver(display2); station.setTemperature(25.0f ); station.setTemperature(30.0f ); } }
4. 工作原理
客户端 创建主题和观察者,将观察者注册到主题。
主题状态变化(setTemperature
)时,调用
notifyObservers
。
所有观察者收到通知,执行 update
更新状态。
5. 优点
解耦 :主题和观察者松耦合,仅通过接口交互。
动态性 :支持运行时添加或移除观察者。
广播 :自动通知所有依赖对象。
6. 缺点
性能开销 :大量观察者时通知可能变慢。
内存泄漏 :未移除的观察者可能导致引用残留。
复杂性 :多观察者时调试困难。
7. 与中介者模式的对比
通信方式
广播
协调
耦合
观察者依赖主题
同事依赖中介者
控制权
主题主动通知
中介者集中控制
8. 实际应用场景
GUI 事件 :按钮点击通知监听器。
数据绑定 :视图随模型变化更新。
消息系统 :发布-订阅模型。
9. 源码中的例子
Java 中的 java.util.Observable
和
Observer
(已废弃,但为经典示例): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.Observable;class Weather extends Observable { private float temp; public void setTemp (float temp) { this .temp = temp; setChanged(); notifyObservers(temp); } } class Display implements java .util.Observer { @Override public void update (Observable o, Object arg) { System.out.println("Temperature: " + arg); } } public class Main { public static void main (String[] args) { Weather weather = new Weather (); weather.addObserver(new Display ()); weather.setTemp(25.0f ); } }
现代替代:java.beans.PropertyChangeSupport
。
10. 总结
观察者模式 通过主题广播状态变化,解耦依赖关系。
Java 实现 依赖接口和列表管理,支持动态通知。
UML 图 展示了主题与观察者的一对多关系。
如果需要推模式(推送数据)与拉模式(观察者拉取)的对比或调整
UML,请告诉我!
状态(State)
状态模式(State
Pattern)是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为,使对象看起来像是改变了其类。状态模式通过将状态封装为独立的对象,简化复杂条件逻辑,提高代码的可维护性和扩展性。
以下是用 Java
实现状态模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 状态模式的定义
核心思想 :将状态抽象为对象,对象根据状态切换行为。
目的 :
消除大量条件语句(如 if-else)。
使状态转换逻辑清晰且可扩展。
适用场景 :
对象行为随状态变化。
状态转换规则复杂。
需要状态机(如订单流程)。
2. 状态模式的结构
上下文(Context) :持有当前状态,委托行为给状态对象。
抽象状态(State) :定义状态接口,声明行为方法。
具体状态(Concrete
State) :实现状态接口,定义具体行为并处理状态转换。
客户端(Client) :创建上下文并触发操作。
Mermaid UML 图
classDiagram
class Context {
-state: State
+setState(State)
+request()
}
class State {
+handle(Context)
}
class ConcreteStateA {
+handle(Context)
}
class ConcreteStateB {
+handle(Context)
}
ConcreteStateA ..|> State : implements
ConcreteStateB ..|> State : implements
Context --> State : uses
ConcreteStateA --> Context : changes state
ConcreteStateB --> Context : changes state
3. Java 实现示例
以下是一个订单状态机的状态模式示例,订单状态在待支付、已支付和已发货之间切换。
3.1 抽象状态
1 2 3 4 public interface OrderState { void handle (Order order) ; }
3.2 具体状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class PendingState implements OrderState { @Override public void handle (Order order) { System.out.println("Order is pending payment" ); order.setState(new PaidState ()); } } public class PaidState implements OrderState { @Override public void handle (Order order) { System.out.println("Order has been paid" ); order.setState(new ShippedState ()); } } public class ShippedState implements OrderState { @Override public void handle (Order order) { System.out.println("Order has been shipped" ); } }
3.3 上下文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Order { private OrderState state; public Order () { this .state = new PendingState (); } public void setState (OrderState state) { this .state = state; } public void process () { state.handle(this ); } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 public class Main { public static void main (String[] args) { Order order = new Order (); order.process(); order.process(); order.process(); } }
4. 工作原理
客户端 创建上下文(Order
),初始状态为
PendingState
。
调用 process()
,上下文委托给当前状态对象执行。
状态对象处理请求并可切换上下文的状态(如从 Pending
到
Paid
)。
5. 优点
清晰性 :状态逻辑封装在独立类中,减少条件分支。
扩展性 :新增状态只需添加新类。
符合开闭原则 :修改行为不需更改上下文。
6. 缺点
类数量增加 :每个状态需定义新类。
复杂度 :小型系统使用状态模式可能显得繁琐。
状态切换管理 :转换逻辑分散在状态类中,可能难跟踪。
7. 与策略模式的对比
目的
状态驱动行为
算法选择
切换
状态内部控制
客户端控制
关注点
状态转换
行为替换
8. 实际应用场景
订单系统 :状态流转(如待支付 → 已支付)。
游戏角色 :角色状态(如站立、行走、跳跃)。
有限状态机 :网络协议状态管理。
9. 源码中的例子
Java 中的 java.nio.channels.SelectionKey
(状态相关):
1 2 SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
10. 总结
状态模式 通过状态对象改变行为,简化状态管理。
Java 实现 依赖接口和状态切换,支持动态行为。
UML 图 展示了上下文与状态的关系。
如果需要复杂状态机(如带条件转换)或调整 UML,请告诉我!
策略(Strategy)
策略模式(Strategy
Pattern)是一种行为型设计模式,它定义了一系列算法或策略,将每个策略封装成独立的对象,使得这些策略可以在运行时动态切换。策略模式通过解耦上下文和具体策略,增强了代码的灵活性和可扩展性。
以下是用 Java
实现策略模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 策略模式的定义
核心思想 :将算法或行为封装为策略对象,上下文根据需要选择策略。
目的 :
消除条件语句(如 if-else)。
支持运行时动态替换行为。
适用场景 :
多个类似行为需动态选择。
算法或策略可能频繁变化。
需要隔离具体实现。
2. 策略模式的结构
抽象策略(Strategy) :定义策略接口,声明行为方法。
具体策略(Concrete
Strategy) :实现策略接口,提供具体算法。
上下文(Context) :持有策略引用,调用策略执行行为。
客户端(Client) :创建上下文并配置策略。
# Mermaid UML 图
classDiagram
class Strategy {
+execute()
}
class ConcreteStrategyA {
+execute()
}
class ConcreteStrategyB {
+execute()
}
class Context {
-strategy: Strategy
+setStrategy(Strategy)
+executeStrategy()
}
class Client
ConcreteStrategyA ..|> Strategy : implements
ConcreteStrategyB ..|> Strategy : implements
Context --> Strategy : uses
Client --> Context : uses
Client --> Strategy : configures
3. Java 实现示例
以下是一个支付系统的策略模式示例,支持不同支付方式。
# 3.1 抽象策略
1 2 3 4 public interface PaymentStrategy { void pay (double amount) ; }
# 3.2 具体策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class CreditCardPayment implements PaymentStrategy { private String cardNumber; public CreditCardPayment (String cardNumber) { this .cardNumber = cardNumber; } @Override public void pay (double amount) { System.out.println("Paid " + amount + " with credit card " + cardNumber); } } public class PayPalPayment implements PaymentStrategy { private String email; public PayPalPayment (String email) { this .email = email; } @Override public void pay (double amount) { System.out.println("Paid " + amount + " with PayPal " + email); } }
# 3.3 上下文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ShoppingCart { private PaymentStrategy paymentStrategy; public void setPaymentStrategy (PaymentStrategy paymentStrategy) { this .paymentStrategy = paymentStrategy; } public void checkout (double amount) { if (paymentStrategy != null ) { paymentStrategy.pay(amount); } else { System.out.println("No payment strategy selected" ); } } }
# 3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Main { public static void main (String[] args) { ShoppingCart cart = new ShoppingCart (); PaymentStrategy creditCard = new CreditCardPayment ("1234-5678-9012-3456" ); cart.setPaymentStrategy(creditCard); cart.checkout(100.0 ); PaymentStrategy payPal = new PayPalPayment ("user@example.com" ); cart.setPaymentStrategy(payPal); cart.checkout(50.0 ); } }
4. 工作原理
客户端 创建上下文(ShoppingCart
)和策略(如
CreditCardPayment
)。
将策略注入上下文(setPaymentStrategy
)。
调用上下文方法(checkout
),执行当前策略的行为。
5. 优点
灵活性 :运行时动态切换策略。
扩展性 :新增策略只需添加新类。
消除条件 :避免大量 if-else 语句。
6. 缺点
类数量增加 :每个策略需定义新类。
客户端复杂性 :客户端需了解并选择策略。
适用性有限 :适合行为差异明显的情况。
7. 与状态模式的对比
目的
算法选择
状态驱动行为
切换控制
客户端控制
状态内部控制
关注点
行为替换
状态转换
8. 实际应用场景
排序算法 :选择不同排序策略(如快排、冒泡)。
支付系统 :动态选择支付方式。
游戏 AI :切换敌人行为策略。
9. 源码中的例子
Java 中的 Comparator
: 1 2 3 List<String> list = Arrays.asList("b" , "a" , "c" ); Collections.sort(list, Comparator.naturalOrder()); Collections.sort(list, Comparator.reverseOrder());
10. 总结
策略模式 通过封装策略对象实现行为动态切换。
Java 实现 依赖接口和组合,支持灵活替换。
UML 图 展示了上下文与策略的关系。
如果需要更复杂示例(如结合工厂模式)或调整 UML,请告诉我!
模板方法(Template
Method)
模板方法模式(Template Method
Pattern)是一种行为型设计模式,它在抽象类中定义了一个操作的算法骨架,将某些步骤的具体实现推迟到子类中。模板方法模式通过固定的流程控制和灵活的实现分离,实现了代码复用和行为定制。
以下是用 Java
实现模板方法模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 模板方法模式的定义
核心思想 :在抽象类中定义算法框架,子类实现具体步骤。
目的 :
适用场景 :
多个类共享固定流程但细节不同。
需要控制算法执行顺序。
提取公共代码。
2. 模板方法模式的结构
抽象类(Abstract
Class) :定义模板方法(算法骨架)和抽象步骤。
具体类(Concrete
Class) :实现抽象步骤,完成具体逻辑。
客户端(Client) :调用模板方法执行算法。
Mermaid UML 图
classDiagram
class AbstractClass {
+templateMethod()
#abstractStep1()
#abstractStep2()
+concreteStep()
}
class ConcreteClass {
#abstractStep1()
#abstractStep2()
}
class Client
ConcreteClass --|> AbstractClass : extends
Client --> AbstractClass : uses
3. Java 实现示例
以下是一个制作饮料的模板方法模式示例,流程固定但配方不同。
3.1 抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public abstract class Beverage { public final void prepareBeverage () { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } private void boilWater () { System.out.println("Boiling water" ); } private void pourInCup () { System.out.println("Pouring into cup" ); } protected abstract void brew () ; protected abstract void addCondiments () ; protected boolean customerWantsCondiments () { return true ; } }
3.2 具体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Coffee extends Beverage { @Override protected void brew () { System.out.println("Brewing coffee grounds" ); } @Override protected void addCondiments () { System.out.println("Adding sugar and milk" ); } } public class Tea extends Beverage { @Override protected void brew () { System.out.println("Steeping tea leaves" ); } @Override protected void addCondiments () { System.out.println("Adding lemon" ); } @Override protected boolean customerWantsCondiments () { return false ; } }
3.3 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Main { public static void main (String[] args) { Beverage coffee = new Coffee (); System.out.println("Making coffee:" ); coffee.prepareBeverage(); Beverage tea = new Tea (); System.out.println("\nMaking tea:" ); tea.prepareBeverage(); } }
4. 工作原理
客户端 创建具体类实例(如 Coffee
或
Tea
)。
调用模板方法(prepareBeverage
),执行固定流程。
子类实现抽象步骤(brew
和
addCondiments
),定制行为。
5. 优点
代码复用 :通用流程在抽象类中定义,避免重复。
控制性 :模板方法控制算法顺序,子类只实现细节。
扩展性 :新增行为只需添加子类。
6. 缺点
类数量增加 :每个新行为需定义新子类。
继承依赖 :子类必须继承抽象类,灵活性受限。
复杂性 :大型系统可能导致继承层次深。
7. 与策略模式的对比
实现方式
继承
组合
控制权
抽象类控制流程
客户端选择策略
灵活性
固定流程
动态切换
8. 实际应用场景
Servlet :HttpServlet
的
service
方法。
游戏流程 :固定游戏循环,子类实现细节。
数据处理 :通用处理框架,子类定制步骤。
9. 源码中的例子
Java 中的 AbstractList
: 1 2 3 4 5 public abstract class AbstractList <E> extends AbstractCollection <E> { public void add (int index, E element) { throw new UnsupportedOperationException (); } }
- 子类如
ArrayList
实现具体逻辑。
10. 总结
模板方法模式 通过抽象类定义算法框架,子类实现细节。
Java 实现 结合继承和抽象方法,支持行为定制。
UML 图 展示了抽象类与具体类的关系。
如果需要更复杂示例(如带钩子方法的多步骤流程)或调整
UML,请告诉我!
访问者(Visitor)
访问者模式(Visitor
Pattern)是一种行为型设计模式,它允许在不修改对象结构的情况下,为对象添加新的操作。访问者模式通过将操作逻辑分离到访问者对象中,实现了数据结构与操作的解耦,特别适用于结构稳定但操作频繁变化的场景。
以下是用 Java
实现访问者模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 访问者模式的定义
核心思想 :将操作封装到访问者对象中,对象结构接受访问者并调用其操作。
目的 :
适用场景 :
对象结构稳定但操作多变。
需要对复杂对象执行多种操作。
数据结构与操作独立演化。
2. 访问者模式的结构
抽象访问者(Visitor) :定义对每个元素类的访问方法。
具体访问者(Concrete Visitor) :实现访问逻辑。
抽象元素(Element) :定义接受访问者的方法。
具体元素(Concrete
Element) :实现接受方法,调用访问者操作。
对象结构(Object
Structure) :包含元素集合,允许访问者遍历。
客户端(Client) :创建结构和访问者,发起访问。
Mermaid UML 图
classDiagram
class Visitor {
+visitElementA(ElementA)
+visitElementB(ElementB)
}
class ConcreteVisitor {
+visitElementA(ElementA)
+visitElementB(ElementB)
}
class Element {
+accept(Visitor)
}
class ElementA {
+accept(Visitor)
}
class ElementB {
+accept(Visitor)
}
class ObjectStructure {
-elements: List<Element>
+accept(Visitor)
}
class Client
ConcreteVisitor ..|> Visitor : implements
ElementA ..|> Element : implements
ElementB ..|> Element : implements
ObjectStructure o--> "many" Element : contains
Element --> Visitor : accepts
Client --> ObjectStructure : uses
Client --> Visitor : uses
3. Java 实现示例
以下是一个计算文件大小的访问者模式示例,访问文件和文件夹。
3.1 抽象元素
1 2 3 4 public interface FileSystemElement { void accept (FileSystemVisitor visitor) ; }
3.2 具体元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class File implements FileSystemElement { private String name; private int size; public File (String name, int size) { this .name = name; this .size = size; } public int getSize () { return size; } @Override public void accept (FileSystemVisitor visitor) { visitor.visit(this ); } } public class Folder implements FileSystemElement { private String name; private List<FileSystemElement> children = new ArrayList <>(); public Folder (String name) { this .name = name; } public void add (FileSystemElement element) { children.add(element); } public List<FileSystemElement> getChildren () { return children; } @Override public void accept (FileSystemVisitor visitor) { visitor.visit(this ); } }
3.3 抽象访问者
1 2 3 4 5 public interface FileSystemVisitor { void visit (File file) ; void visit (Folder folder) ; }
3.4 具体访问者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class SizeCalculatorVisitor implements FileSystemVisitor { private int totalSize = 0 ; @Override public void visit (File file) { totalSize += file.getSize(); } @Override public void visit (Folder folder) { for (FileSystemElement element : folder.getChildren()) { element.accept(this ); } } public int getTotalSize () { return totalSize; } }
3.5 对象结构(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class FileSystem { private List<FileSystemElement> elements = new ArrayList <>(); public void addElement (FileSystemElement element) { elements.add(element); } public void accept (FileSystemVisitor visitor) { for (FileSystemElement element : elements) { element.accept(visitor); } } }
3.6 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Main { public static void main (String[] args) { File file1 = new File ("doc1.txt" , 100 ); File file2 = new File ("doc2.txt" , 200 ); Folder folder = new Folder ("Documents" ); folder.add(file1); folder.add(file2); FileSystem fileSystem = new FileSystem (); fileSystem.addElement(folder); SizeCalculatorVisitor sizeVisitor = new SizeCalculatorVisitor (); fileSystem.accept(sizeVisitor); System.out.println("Total size: " + sizeVisitor.getTotalSize()); } }
4. 工作原理
客户端 创建对象结构(FileSystem
)和具体元素(File
和 Folder
)。
创建访问者(SizeCalculatorVisitor
)并传递给结构。
元素通过 accept
调用访问者的对应方法,执行操作。
5. 优点
扩展性 :新增操作只需添加新访问者。
解耦 :数据结构与操作分离。
集中逻辑 :操作集中在访问者中。
6. 缺点
结构稳定要求 :元素类变化会影响所有访问者。
复杂度 :增加访问者类,提高系统复杂性。
访问限制 :需暴露元素接口给访问者。
7. 与迭代器模式的对比
目的
扩展操作
顺序访问
关注点
操作逻辑
遍历逻辑
控制权
访问者控制
客户端控制
8. 实际应用场景
编译器 :语法树遍历和操作(如类型检查)。
文档处理 :对文档元素执行统计或格式化。
游戏 :对不同对象执行渲染或碰撞检测。
9. 源码中的例子
Java 中的 javax.swing.tree.TreeVisitor
(概念类似):
1 2 3 4 interface TreeVisitor { void visit (Node node) ; }
10. 总结
访问者模式 通过访问者分离操作和结构,支持动态功能扩展。
Java 实现 依赖双重分派(accept
和
visit
),实现灵活操作。
UML 图 展示了访问者与元素的关系。
如果需要更复杂示例(如多访问者)或调整 UML,请告诉我!
扩展模式(Extended Patterns)
依赖注入(Dependency
Injection)
依赖注入模式(Dependency Injection Pattern,简称
DI)是一种设计模式,用于实现控制反转(Inversion of
Control,IoC)。它通过将对象的依赖关系从对象内部创建转移到外部注入,从而解耦对象的创建和使用,提高代码的灵活性、可测试性和可维护性。依赖注入是
IoC 的一种具体实现方式。
以下是用 Java
实现依赖注入模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 依赖注入模式的定义
核心思想 :将对象的依赖(即所需的服务或组件)从外部注入,而不是由对象自己创建。
目的 :
解耦对象的创建和使用。
提高代码的可测试性(易于 mock 依赖)。
支持动态配置和替换依赖。
适用场景 :
对象依赖复杂或需频繁更换。
单元测试需要隔离依赖。
系统需要集中管理组件。
2. 依赖注入模式的结构
服务(Service) :被注入的依赖,提供具体功能。
客户端(Client) :依赖服务的对象,使用注入的依赖。
注入器(Injector) :负责创建和注入依赖,可以是手动实现或框架(如
Spring)。
接口(Interface) :定义服务契约,解耦客户端和具体实现。
Mermaid UML 图
classDiagram
class Service {
<<interface>>
+doSomething()
}
class ConcreteService {
+doSomething()
}
class Client {
-service: Service
+setService(Service)
+useService()
}
class Injector {
+injectDependencies(Client)
}
ConcreteService ..|> Service : implements
Client --> Service : uses
Injector --> Client : injects
Injector --> ConcreteService : creates
3. 依赖注入的类型
构造函数注入 :通过构造函数传递依赖。
Setter 注入 :通过 setter 方法设置依赖。
接口注入 :通过接口定义注入方法(较少使用)。
4. Java 实现示例
以下是一个消息服务的依赖注入示例,展示构造函数和 Setter 注入。
4.1 服务接口
1 2 3 4 public interface MessageService { void sendMessage (String message) ; }
4.2 具体服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class EmailService implements MessageService { @Override public void sendMessage (String message) { System.out.println("Sending email: " + message); } } public class SMSService implements MessageService { @Override public void sendMessage (String message) { System.out.println("Sending SMS: " + message); } }
4.3 客户端(构造函数注入)
1 2 3 4 5 6 7 8 9 10 11 12 public class MessageSenderConstructor { private final MessageService service; public MessageSenderConstructor (MessageService service) { this .service = service; } public void send (String message) { service.sendMessage(message); } }
4.4 客户端(Setter 注入)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MessageSenderSetter { private MessageService service; public void setService (MessageService service) { this .service = service; } public void send (String message) { if (service != null ) { service.sendMessage(message); } else { System.out.println("Service not set" ); } } }
4.5 注入器(手动实现)
1 2 3 4 5 6 7 8 9 10 11 12 public class DependencyInjector { public static MessageSenderConstructor createConstructorSender () { return new MessageSenderConstructor (new EmailService ()); } public static MessageSenderSetter createSetterSender () { MessageSenderSetter sender = new MessageSenderSetter (); sender.setService(new SMSService ()); return sender; } }
4.6 客户端代码
1 2 3 4 5 6 7 8 9 10 11 public class Main { public static void main (String[] args) { MessageSenderConstructor constructorSender = DependencyInjector.createConstructorSender(); constructorSender.send("Hello via email" ); MessageSenderSetter setterSender = DependencyInjector.createSetterSender(); setterSender.send("Hello via SMS" ); } }
5. 工作原理
客户端 定义依赖接口(MessageService
),不直接创建实例。
注入器 创建具体服务(如
EmailService
)并注入客户端。
客户端通过接口调用服务,完成功能。
6. 优点
解耦 :客户端不依赖具体实现,只依赖接口。
可测试性 :易于注入 mock 对象进行测试。
灵活性 :运行时可切换依赖实现。
7. 缺点
复杂度 :手动注入增加代码量,需依赖框架简化。
运行时错误 :依赖未注入可能导致空指针异常。
学习曲线 :理解 IoC 和 DI 需一定经验。
8. 与工厂模式的对比
创建方式
外部注入
工厂创建
控制权
注入器控制
客户端控制
耦合
更低(接口依赖)
较高(工厂依赖)
9. 实际应用场景
Spring 框架 :通过 @Autowired
注入依赖。
单元测试 :注入 mock 对象(如 Mockito)。
模块化系统 :动态配置服务。
10. 源码中的例子(Spring 示例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Component class MessageSender { private final MessageService service; @Autowired public MessageSender (MessageService service) { this .service = service; } public void send (String message) { service.sendMessage(message); } } @Component class EmailService implements MessageService { @Override public void sendMessage (String message) { System.out.println("Email: " + message); } }
11. 总结
依赖注入模式 通过外部注入解耦依赖关系。
Java 实现 支持构造函数和 Setter
注入,手动或框架实现。
UML 图 展示了服务、客户端和注入器的关系。
如果需要框架(如 Spring)示例或调整 UML,请告诉我!
发布-订阅(Publish-Subscribe)
发布订阅模式(Publish-Subscribe Pattern,简称
Pub/Sub)是一种消息传递模式,虽然它与观察者模式(Observer
Pattern)有相似之处,但它更强调松耦合的异步通信。发布订阅模式通过一个中间消息代理(Broker)实现发布者(Publisher)和订阅者(Subscriber)之间的解耦,订阅者无需直接依赖发布者。
以下是用 Java
实现发布订阅模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 发布订阅模式的定义
核心思想 :发布者发送消息到中间代理,订阅者通过订阅主题或频道接收消息。
目的 :
适用场景 :
事件驱动系统(如 GUI 事件)。
消息队列(如 Kafka、RabbitMQ)。
实时通知(如股票价格更新)。
2. 发布订阅模式的结构
发布者(Publisher) :生成并发送消息。
订阅者(Subscriber) :接收感兴趣的消息。
消息代理(Broker) :管理订阅关系,分发消息。
主题(Topic) :消息的分类,订阅者订阅特定主题。
客户端(Client) :创建发布者和订阅者,发起交互。
Mermaid UML 图
classDiagram
class Publisher {
+publish(topic, message)
}
class Subscriber {
+receive(topic, message)
}
class MessageBroker {
-subscriptions: Map<Topic, List<Subscriber>>
+subscribe(topic, Subscriber)
+unsubscribe(topic, Subscriber)
+publish(topic, message)
}
class Client
MessageBroker --> Publisher : receives from
MessageBroker --> Subscriber : notifies
Client --> Publisher : uses
Client --> Subscriber : uses
Client --> MessageBroker : configures
3. Java 实现示例
以下是一个简单的事件通知系统的发布订阅模式示例。
3.1 消息代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MessageBroker { private Map<String, List<Subscriber>> subscriptions = new HashMap <>(); public void subscribe (String topic, Subscriber subscriber) { subscriptions.computeIfAbsent(topic, k -> new ArrayList <>()).add(subscriber); } public void unsubscribe (String topic, Subscriber subscriber) { List<Subscriber> subscribers = subscriptions.get(topic); if (subscribers != null ) { subscribers.remove(subscriber); } } public void publish (String topic, String message) { List<Subscriber> subscribers = subscriptions.get(topic); if (subscribers != null ) { for (Subscriber subscriber : subscribers) { subscriber.receive(topic, message); } } } }
3.2 订阅者接口
1 2 3 4 public interface Subscriber { void receive (String topic, String message) ; }
3.3 具体订阅者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class EmailSubscriber implements Subscriber { private String name; public EmailSubscriber (String name) { this .name = name; } @Override public void receive (String topic, String message) { System.out.println(name + " received email on " + topic + ": " + message); } } public class SMSSubscriber implements Subscriber { private String name; public SMSSubscriber (String name) { this .name = name; } @Override public void receive (String topic, String message) { System.out.println(name + " received SMS on " + topic + ": " + message); } }
3.4 发布者
1 2 3 4 5 6 7 8 9 10 11 12 public class NewsPublisher { private MessageBroker broker; public NewsPublisher (MessageBroker broker) { this .broker = broker; } public void publish (String topic, String message) { broker.publish(topic, message); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Main { public static void main (String[] args) { MessageBroker broker = new MessageBroker (); Subscriber emailSub = new EmailSubscriber ("Alice" ); Subscriber smsSub = new SMSSubscriber ("Bob" ); broker.subscribe("news" , emailSub); broker.subscribe("news" , smsSub); NewsPublisher publisher = new NewsPublisher (broker); publisher.publish("news" , "Breaking news!" ); broker.unsubscribe("news" , smsSub); publisher.publish("news" , "Update!" ); } }
4. 工作原理
客户端 创建消息代理、订阅者和发布者。
订阅者通过代理订阅主题(subscribe
)。
发布者发送消息到代理(publish
),代理分发给订阅者(receive
)。
5. 优点
解耦 :发布者和订阅者无直接依赖,仅通过代理交互。
灵活性 :支持动态订阅和取消。
异步性 :可结合队列实现异步通信。
6. 缺点
复杂度 :代理增加系统复杂性。
性能 :大量订阅者或消息可能影响分发效率。
依赖代理 :代理故障影响整个系统。
7. 与观察者模式的对比
耦合
松耦合(通过代理)
紧耦合(直接依赖主题)
中介
有独立代理
无(主题直接通知)
通信
异步支持强
通常同步
8. 实际应用场景
消息队列 :如 Kafka、RabbitMQ。
事件总线 :GUI 框架中的事件分发。
实时系统 :股票价格通知。
9. 源码中的例子
Java 中的 java.util.concurrent.Flow
(Java 9+):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.concurrent.Flow.*;class MyPublisher implements Publisher <String> { private List<Subscriber<? super String>> subscribers = new ArrayList <>(); @Override public void subscribe (Subscriber<? super String> subscriber) { subscribers.add(subscriber); subscriber.onSubscribe(new Subscription () { @Override public void request (long n) {} @Override public void cancel () {} }); } public void publish (String message) { subscribers.forEach(s -> s.onNext(message)); } }
10. 总结
发布订阅模式 通过代理实现松耦合消息传递。
Java 实现 依赖代理分发,支持动态订阅。
UML 图 展示了发布者、订阅者和代理的关系。
如果需要异步示例(如线程池)或调整 UML,请告诉我!
模块模式(Module
Pattern)
我假设你指的是“模块模式”(Module
Pattern),可能是“模块”中的拼写或表述差异。模块模式不是经典的 GoF
设计模式,而是一种在 JavaScript
中广泛使用的设计模式,用于封装代码、隐藏实现细节并提供公共接口。它通过闭包和立即执行函数(IIFE)实现私有作用域和模块化。
由于你的问题要求用 Java,而 Java 的模块化机制与 JavaScript 不同(如
Java 使用类和包),我将讲解模块模式的核心思想,并将其适配到 Java
环境中,提供类似的实现方式(基于类的封装或 Java 9+
的模块系统)。以下是详细讲解。
1. 模块模式的定义
核心思想 :通过封装隐藏私有成员,只暴露公共接口,实现数据隐私和模块化。
目的 :
防止全局命名空间污染。
提供清晰的 API,隐藏实现细节。
适用场景 :
需要封装逻辑和状态。
避免变量冲突。
分离关注点。
2. 模块模式的结构(JavaScript
视角)
私有成员 :通过闭包定义的变量和方法,仅模块内部可访问。
公共接口 :通过返回的对象暴露给外部。
立即执行函数(IIFE) :创建模块作用域。
JavaScript 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var CounterModule = (function ( ) { var count = 0 ; function incrementInternal ( ) { count++; } return { increment : function ( ) { incrementInternal (); console .log ("Count: " + count); }, getCount : function ( ) { return count; } }; })(); CounterModule .increment (); CounterModule .increment (); console .log (CounterModule .getCount ());
3. Java 中的模块模式适配
Java 没有闭包和
IIFE,但可以通过类的封装(私有字段和公共方法)实现类似效果。Java 9
引入的模块系统(JPMS)进一步支持模块化。以下是两种方式的实现。
3.1 使用类封装(类似
JavaScript 模块模式)
模块类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class CounterModule { private int count = 0 ; private void incrementInternal () { count++; } public void increment () { incrementInternal(); System.out.println("Count: " + count); } public int getCount () { return count; } private static final CounterModule INSTANCE = new CounterModule (); private CounterModule () {} public static CounterModule getInstance () { return INSTANCE; } }
客户端代码
1 2 3 4 5 6 7 8 public class Main { public static void main (String[] args) { CounterModule counter = CounterModule.getInstance(); counter.increment(); counter.increment(); System.out.println("Current count: " + counter.getCount()); } }
说明 :
私有字段 count
和方法 incrementInternal
隐藏实现。
公共方法 increment
和 getCount
暴露接口。
单例模式模拟 JavaScript 的单一模块实例。
3.2 使用 Java 9+ 模块系统(JPMS)
Java 9 引入的模块系统提供了更高级的模块化支持,通过
module-info.java
定义模块边界。
模块定义(module-info.java)
1 2 3 module counterModule { exports com.example.counter; }
模块实现(com.example.counter.CounterModule)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.example.counter;public class CounterModule { private int count = 0 ; private void incrementInternal () { count++; } public void increment () { incrementInternal(); System.out.println("Count: " + count); } public int getCount () { return count; } }
客户端模块(module-info.java)
1 2 3 module client { requires counterModule; }
客户端代码(com.example.client.Main)
1 2 3 4 5 6 7 8 9 10 11 package com.example.client;import com.example.counter.CounterModule;public class Main { public static void main (String[] args) { CounterModule counter = new CounterModule (); counter.increment(); counter.increment(); } }
说明 :
module-info.java
定义模块边界,控制包的可见性。
类似 JavaScript 的模块作用域,但更静态。
4. 工作原理
封装 :私有成员(如
count
)隐藏在类或模块内部。
暴露接口 :通过公共方法(如
increment
)提供访问。
客户端 :仅通过接口操作模块,无需了解实现。
5. 优点
封装性 :隐藏实现细节,保护数据。
模块化 :逻辑清晰,便于维护。
复用性 :单一模块可多次使用。
6. 缺点
灵活性低 :Java 类封装静态,动态性不如
JavaScript。
单例限制 :单例模式可能不适合所有场景。
JPMS 复杂性 :模块系统配置较繁琐。
7. 与工厂模式的对比
目的
封装和模块化
创建对象
结构
单一实例或模块
工厂类
动态性
较静态
动态创建
8. 实际应用场景
工具类 :封装工具函数(如 Math
类)。
配置管理 :隐藏配置细节,提供接口。
服务模块 :如日志或缓存服务。
9. 源码中的例子
Java 中的 java.util.Collections
: 1 2 3 4 import java.util.Collections;List<String> list = new ArrayList <>(); Collections.sort(list);
-
说明 :Collections
封装排序逻辑,隐藏实现。
10. 总结
模块模式 通过封装实现私有性和公共接口。
Java 实现 可用类封装或 JPMS,模拟 JavaScript
模块化。
UML 图 (若需要)可展示单一模块与客户端关系。
如果需要更复杂示例(如带配置的模块)或 UML 图,请告诉我!
MVC(Model-View-Controller)
MVC 模式(Model-View-Controller
Pattern)是一种广泛使用的架构模式,用于组织代码,分分离用户界面、数据和控制逻辑。它通过将应用程序分为三个相互连接的部分,提高了代码的可维护性、可扩展性和模块化。
以下是用 Java 实现 MVC
模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. MVC 模式的定义
核心思想 :将应用程序分为模型(Model)、视图(View)和控制器(Controller),实现职责分离。
目的 :
适用场景 :
GUI 应用程序(如 Swing、JavaFX)。
Web 应用(如 Spring MVC)。
复杂交互系统。
2. MVC 模式的结构
模型(Model) :管理数据和业务逻辑,独立于 UI。
视图(View) :显示模型数据,负责用户界面。
控制器(Controller) :处理用户输入,协调模型和视图。
交互关系 :
控制器接收用户输入,更新模型。
模型通知视图更新显示。
视图从模型获取数据。
Mermaid UML 图
classDiagram
class Model {
-data: Data
+setData(data)
+getData() Data
+notifyViews()
}
class View {
-model: Model
+update()
+display()
}
class Controller {
-model: Model
-view: View
+handleInput(input)
}
Model --> View : notifies
View --> Model : queries
Controller --> Model : updates
Controller --> View : controls
3. Java 实现示例
以下是一个简单的计数器应用的 MVC 示例。
3.1 模型(Model)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class CounterModel { private int count; private List<View> views = new ArrayList <>(); public void increment () { count++; notifyViews(); } public void decrement () { count--; notifyViews(); } public int getCount () { return count; } public void addView (View view) { views.add(view); view.update(); } private void notifyViews () { for (View view : views) { view.update(); } } }
3.2 视图(View)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CounterView implements View { private CounterModel model; public CounterView (CounterModel model) { this .model = model; model.addView(this ); } @Override public void update () { System.out.println("Current count: " + model.getCount()); } } interface View { void update () ; }
3.3 控制器(Controller)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class CounterController { private CounterModel model; private CounterView view; public CounterController (CounterModel model, CounterView view) { this .model = model; this .view = view; } public void increment () { model.increment(); } public void decrement () { model.decrement(); } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 public class Main { public static void main (String[] args) { CounterModel model = new CounterModel (); CounterView view = new CounterView (model); CounterController controller = new CounterController (model, view); controller.increment(); controller.increment(); controller.decrement(); } }
4. 工作原理
客户端 创建模型、视图和控制器,关联三者。
用户通过控制器发起操作(如 increment
)。
控制器更新模型,模型通知视图刷新显示。
5. 优点
解耦 :模型、视图和控制器独立,互不干扰。
可扩展 :易于添加新视图或控制器。
可测试 :模型独立于 UI,便于单元测试。
6. 缺点
复杂度 :小型应用可能显得过于繁琐。
耦合风险 :视图和控制器可能间接耦合。
维护成本 :多组件增加协调难度。
7. 与 MVP/MVVM 的对比
控制器角色
协调视图和模型
主动更新视图
数据绑定
视图依赖
依赖模型
依赖 Presenter
通过 ViewModel 绑定
耦合
中等
较低
最低
8. 实际应用场景
Swing/JavaFX :GUI 组件分离。
Spring MVC :Web 应用框架。
游戏开发 :游戏逻辑与渲染分离。
9. 源码中的例子
Java Swing 中的 MVC: 1 2 JButton button = new JButton ("Click" );button.addActionListener(e -> System.out.println("Clicked" ));
-
Model :按钮状态。 - View :按钮 UI。 -
Controller :ActionListener
。
10. 总结
MVC
模式 通过分离模型、视图和控制器实现职责分工。
Java 实现 依赖观察者机制协调视图更新。
UML 图 展示了三者之间的关系。
如果需要更复杂示例(如多视图支持)或调整 UML,请告诉我!
MVP(Model-View-Presenter)
MVP 模式(Model-View-Presenter Pattern)是一种架构模式,演变自 MVC
模式,旨在进一步解耦视图和逻辑,增强可测试性。MVP
通过将视图(View)和模型(Model)之间的交互完全交给展示者(Presenter)处理,避免了视图直接依赖模型,提高了代码的模块化和清晰度。
以下是用 Java 实现 MVP
模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. MVP 模式的定义
核心思想 :通过展示者(Presenter)协调视图和模型,视图只负责显示,Presenter
处理逻辑。
目的 :
适用场景 :
GUI 应用程序需要清晰分离。
需要测试业务逻辑而不依赖 UI。
视图逻辑复杂。
2. MVP 模式的结构
模型(Model) :管理数据和业务逻辑,与 MVC
类似。
视图(View) :显示数据和用户界面,定义与 Presenter
交互的接口。
展示者(Presenter) :处理用户输入,更新模型并控制视图。
客户端(Client) :创建并连接组件。
Mermaid UML 图
classDiagram
class Model {
-data: Data
+setData(data)
+getData() Data
}
class View {
<<interface>>
+showData(data)
+getInput() Input
}
class ConcreteView {
+showData(data)
+getInput() Input
}
class Presenter {
-model: Model
-view: View
+handleInput(input)
}
class Client
ConcreteView ..|> View : implements
Presenter --> Model : updates
Presenter --> View : controls
ConcreteView --> Presenter : notifies
Client --> Presenter : uses
Client --> ConcreteView : uses
3. Java 实现示例
以下是一个计数器的 MVP 示例,Presenter 处理增减逻辑。
3.1 模型(Model)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class CounterModel { private int count; public void increment () { count++; } public void decrement () { count--; } public int getCount () { return count; } }
3.2 视图接口(View)
1 2 3 4 5 6 public interface CounterView { void showCount (int count) ; void incrementClicked () ; void decrementClicked () ; }
3.3 具体视图(Concrete View)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class ConsoleCounterView implements CounterView { private CounterPresenter presenter; public ConsoleCounterView (CounterPresenter presenter) { this .presenter = presenter; } @Override public void showCount (int count) { System.out.println("Current count: " + count); } @Override public void incrementClicked () { presenter.increment(); } @Override public void decrementClicked () { presenter.decrement(); } public void simulateUserInteraction () { incrementClicked(); decrementClicked(); } }
3.4 展示者(Presenter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CounterPresenter { private CounterModel model; private CounterView view; public CounterPresenter (CounterModel model, CounterView view) { this .model = model; this .view = view; } public void increment () { model.increment(); view.showCount(model.getCount()); } public void decrement () { model.decrement(); view.showCount(model.getCount()); } }
3.5 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Main { public static void main (String[] args) { CounterModel model = new CounterModel (); ConsoleCounterView view = new ConsoleCounterView (null ); CounterPresenter presenter = new CounterPresenter (model, view); view.presenter = presenter; view.simulateUserInteraction(); } }
4. 工作原理
客户端 创建模型、视图和展示者,关联三者。
视图捕获用户输入(如 incrementClicked
),通知
Presenter。
Presenter 更新模型并调用视图方法刷新显示。
5. 优点
解耦 :视图不直接访问模型,依赖 Presenter。
可测试性 :Presenter 无 UI 依赖,易于单元测试。
清晰性 :职责明确,逻辑集中。
6. 缺点
复杂度 :小型应用可能显得繁琐。
类数量 :增加接口和实现类。
双向依赖 :视图和 Presenter 可能形成循环引用。
7. 与 MVC 的对比
视图依赖
不依赖模型
依赖模型
控制角色
Presenter 主动更新视图
Controller 协调
通信
双向(View ↔︎ Presenter)
三方(View ↔︎ Controller ↔︎ Model)
8. 实际应用场景
Android 开发 :Activity/View 作为视图,Presenter
处理逻辑。
桌面应用 :Swing/JavaFX 的逻辑分离。
测试驱动开发 :隔离 UI 进行测试。
9. 源码中的例子
Android 中的 MVP(伪代码): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface LoginView { void showLoginSuccess () ; } public class LoginPresenter { private LoginView view; private LoginModel model; public LoginPresenter (LoginView view, LoginModel model) { this .view = view; this .model = model; } public void login (String username, String password) { if (model.validate(username, password)) { view.showLoginSuccess(); } } }
10. 总结
MVP 模式 通过 Presenter
分离视图和模型,增强解耦。
Java 实现 依赖接口和双向通信,支持灵活控制。
UML 图 展示了视图、Presenter 和模型的关系。
如果需要更复杂示例(如多视图)或调整 UML,请告诉我!
MVVM(Model-View-ViewModel)
MVVM 模式(Model-View-ViewModel Pattern)是一种架构模式,起源于微软的
WPF 和 Silverlight,广泛应用于现代前端框架(如
Angular、Vue.js)和桌面应用开发。它通过引入 ViewModel
层,将视图(View)和模型(Model)解耦,并利用数据绑定简化视图更新。MVVM
模式特别适合双向数据绑定的场景。
以下是用 Java 实现 MVVM
模式的详细讲解,包括定义、结构、代码示例及其优缺点。由于 Java
不原生支持双向数据绑定,我会通过观察者机制模拟绑定效果。
1. MVVM 模式的定义
核心思想 :通过 ViewModel
连接视图和模型,利用数据绑定实现视图与数据的自动同步。
目的 :
解耦视图和业务逻辑。
简化视图更新,提高开发效率。
适用场景 :
视图频繁更新(如表单、实时数据)。
支持数据绑定的 UI 框架。
需要清晰分离 UI 和逻辑。
2. MVVM 模式的结构
模型(Model) :管理数据和业务逻辑。
视图(View) :显示数据,响应用户输入。
视图模型(ViewModel) :持有视图所需数据,处理逻辑,绑定模型和视图。
绑定机制(Binding) :同步 View 和 ViewModel(Java
中需手动模拟)。
客户端(Client) :创建组件并启动应用。
Mermaid UML 图
classDiagram
class Model {
-data: Data
+setData(data)
+getData() Data
}
class View {
+display(data)
+notifyInput(input)
}
class ViewModel {
-model: Model
-observers: List<View>
+setValue(value)
+getValue() Value
+notifyViews()
}
class Client
ViewModel --> Model : uses
View --> ViewModel : binds to
ViewModel --> View : notifies
Client --> View : uses
Client --> ViewModel : uses
3. Java 实现示例
以下是一个计数器的 MVVM 示例,ViewModel
管理计数并通过观察者通知视图。
3.1 模型(Model)
1 2 3 4 5 6 7 8 9 10 11 12 public class CounterModel { private int count; public void setCount (int count) { this .count = count; } public int getCount () { return count; } }
3.2 视图(View)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class CounterView { private CounterViewModel viewModel; public CounterView (CounterViewModel viewModel) { this .viewModel = viewModel; viewModel.addObserver(this ::update); update(viewModel.getValue()); } public void update (int count) { System.out.println("View updated - Count: " + count); } public void increment () { viewModel.setValue(viewModel.getValue() + 1 ); } public void decrement () { viewModel.setValue(viewModel.getValue() - 1 ); } }
3.3 视图模型(ViewModel)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class CounterViewModel { private CounterModel model; private List<Consumer<Integer>> observers = new ArrayList <>(); public CounterViewModel (CounterModel model) { this .model = model; } public void setValue (int value) { model.setCount(value); notifyViews(); } public int getValue () { return model.getCount(); } public void addObserver (Consumer<Integer> observer) { observers.add(observer); } private void notifyViews () { observers.forEach(observer -> observer.accept(model.getCount())); } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 public class Main { public static void main (String[] args) { CounterModel model = new CounterModel (); CounterViewModel viewModel = new CounterViewModel (model); CounterView view = new CounterView (viewModel); view.increment(); view.increment(); view.decrement(); } }
4. 工作原理
客户端 创建模型、ViewModel 和视图,关联三者。
视图绑定到 ViewModel,监听数据变化。
用户通过视图发起操作(如 increment
),ViewModel
更新模型并通知视图刷新。
5. 优点
解耦 :视图不直接访问模型,依赖 ViewModel。
自动化 :数据绑定减少手动更新代码。
可测试性 :ViewModel 独立于 UI,易于测试。
6. 缺点
复杂度 :绑定机制增加实现难度(Java
中需手动)。
性能 :大量绑定可能影响效率。
适用性 :需框架支持(如
JavaFX)才充分发挥优势。
7. 与 MVC/MVP 的对比
视图更新
数据绑定
Controller 控制
Presenter 控制
视图依赖
ViewModel
Model
Presenter
耦合
最低
中等
较低
8. 实际应用场景
JavaFX :绑定属性到 UI。
前端框架 :Vue.js、WPF 的 MVVM。
表单应用 :实时同步输入和数据。
9. 源码中的例子(JavaFX)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import javafx.beans.property.IntegerProperty;import javafx.beans.property.SimpleIntegerProperty;public class CounterViewModel { private IntegerProperty count = new SimpleIntegerProperty (0 ); public void increment () { count.set(count.get() + 1 ); } public IntegerProperty countProperty () { return count; } } class Main { public static void main (String[] args) { CounterViewModel vm = new CounterViewModel (); vm.countProperty().addListener((obs, old, newVal) -> System.out.println("Count: " + newVal)); vm.increment(); } }
10. 总结
MVVM 模式 通过 ViewModel 和绑定解耦视图和模型。
Java
实现 需手动模拟绑定(如观察者),框架支持更佳。
UML 图 展示了 ViewModel 的中介作用。
如果需要更复杂示例(如双向绑定)或调整 UML,请告诉我!
MVC, MVP, MVVM 比较
以下是 MVC(Model-View-Controller)、MVP(Model-View-Presenter)和
MVVM(Model-View-ViewModel)三种架构模式的详细比较表格,涵盖定义、结构、职责、耦合性、数据流、测试性等关键方面。
定义
通过控制器协调模型和视图,分离数据、UI 和逻辑。
通过展示者处理视图和模型交互,视图不直接访问模型。
通过 ViewModel 和数据绑定解耦视图和模型,强调自动化。
核心思想
视图显示模型,控制器处理输入,模型管理数据。
Presenter 控制视图和模型,视图被动接收更新。
ViewModel 暴露数据和命令,视图通过绑定自动更新。
结构
- Model: 数据和逻辑 - View: UI - Controller: 协调
- Model: 数据和逻辑 - View: UI 接口 - Presenter: 逻辑
- Model: 数据和逻辑 - View: UI - ViewModel: 中介
职责分配
- Model: 数据存储和业务逻辑 - View: 显示和输入 - Controller:
更新模型、控制视图
- Model: 数据存储和逻辑 - View: 显示和通知 - Presenter:
处理输入、更新视图
- Model: 数据和逻辑 - View: 显示 - ViewModel:
数据绑定和逻辑
耦合性
中等:View 直接依赖 Model,Controller 依赖两者
较低:View 只依赖 Presenter,Presenter 依赖 Model
最低:View 通过绑定依赖 ViewModel,ViewModel 依赖 Model
数据流
- 用户 → Controller → Model → View
- 用户 → View → Presenter → Model → View
- 用户 → View → ViewModel → Model(绑定双向同步)
视图更新
Controller 主动更新 View
Presenter 主动更新 View
数据绑定自动更新 View
控制器/Presenter/ViewModel 角色
Controller 协调模型和视图更新
Presenter 处理逻辑,主动控制视图
ViewModel 暴露数据和命令,视图绑定更新
通信方式
- View → Controller (输入) - Model → View (通知)
- View → Presenter (通知) - Presenter → View (更新)
- View ↔︎ ViewModel (绑定) - ViewModel → Model (更新)
测试性
Model 可独立测试,Controller 依赖 UI 难测
Presenter 可独立测试,View 可 mock
ViewModel 可独立测试,View 可 mock
复杂度
中等:简单应用可能繁琐
中等:需定义接口和实现
较高:绑定机制增加复杂性(Java 需手动实现)
优点
- 解耦 UI 和逻辑 - 易于理解
- 视图与模型解耦 - 高测试性
- 视图自动更新 - 最低耦合
缺点
- View 依赖 Model - 控制器可能臃肿
- 类数量增加 - View-Presenter 双向依赖
- 绑定复杂 - 性能开销(大量绑定)
适用场景
- 传统 GUI - Web 应用(如 Spring MVC)
- 测试驱动开发 - 复杂视图逻辑
- 数据驱动 UI - 支持绑定的框架(如 JavaFX)
Java 示例
Controller 更新 Model,Model 通知 View
Presenter 处理输入,调用 View 更新
ViewModel 绑定数据,View 自动更新
典型框架
Spring MVC、Struts
Android (早期)、GWT
JavaFX、WPF、Vue.js
详细说明
数据流
MVC :用户输入通过控制器传递到模型,模型更新后通知视图显示(单向为主,视图可直接查询模型)。
MVP :用户输入通过视图通知 Presenter,Presenter
更新模型并主动刷新视图(双向通信)。
MVVM :用户输入直接影响
ViewModel(通过绑定),ViewModel
更新模型,视图自动同步(双向绑定)。
视图与模型关系
MVC :视图直接访问模型获取数据,可能导致耦合。
MVP :视图通过 Presenter
间接访问模型,解耦更彻底。
MVVM :视图通过 ViewModel
绑定访问数据,完全隔离模型。
测试性
MVC :控制器依赖视图,测试需模拟 UI。
MVP :Presenter 不依赖具体视图实现,可轻松 mock View
接口。
MVVM :ViewModel
独立于视图,测试只需验证数据逻辑。
Java 示例代码片段
MVC : 1 2 3 4 5 6 class Model { int count; void setCount (int c) { count = c; } }class View { void show (int count) { System.out.println(count); } }class Controller { Model m; View v; void increment () { m.setCount(m.count + 1 ); v.show(m.count); } }
MVP : 1 2 3 interface View { void show (int count) ; }class Model { int count; void setCount (int c) { count = c; } }class Presenter { Model m; View v; void increment () { m.setCount(m.count + 1 ); v.show(m.count); } }
MVVM : 1 2 3 4 5 6 class Model { int count; void setCount (int c) { count = c; } }class ViewModel { Model m; Consumer<Integer> observer; void setValue (int v) { m.setCount(v); observer.accept(v); } } class View { ViewModel vm; void bind () { vm.observer = this ::show; } void show (int v) { System.out.println(v); } }
总结
MVC :适合传统应用,视图与模型直接交互。
MVP :增强解耦,Presenter 主动控制,利于测试。
MVVM :依赖数据绑定,视图最被动,适合现代 UI
框架。
如果需要更具体示例或调整表格内容,请告诉我!
仓储模式(Repository
Pattern)
仓储模式(Repository
Pattern)是一种设计模式,广泛用于数据访问层,旨在将数据访问逻辑从业务逻辑中分离出来。它通过提供一个类似集合的接口来操作数据,隐藏底层数据存储的实现细节(如数据库、文件系统),从而解耦应用程序与数据源。
以下是用 Java
实现仓储模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 仓储模式的定义
核心思想 :通过仓储对象提供对数据的统一访问接口,封装数据操作逻辑。
目的 :
解耦业务逻辑与数据访问。
提供一致的数据操作方式。
便于测试和替换数据源。
适用场景 :
需要隔离数据库操作。
数据源可能切换(如从 SQL 到 NoSQL)。
单元测试需要 mock 数据访问。
2. 仓储模式的结构
领域模型(Domain
Model) :表示业务实体的数据结构。
仓储接口(Repository
Interface) :定义数据操作的抽象方法。
具体仓储(Concrete
Repository) :实现仓储接口,封装数据访问逻辑。
数据存储(Data
Store) :底层数据源(如数据库、文件)。
客户端(Client) :使用仓储访问数据。
Mermaid UML 图
classDiagram
class DomainModel {
-id: int
-name: String
}
class Repository {
<<interface>>
+add(entity: DomainModel)
+findById(id: int) DomainModel
+remove(id: int)
}
class ConcreteRepository {
-dataStore: DataStore
+add(entity: DomainModel)
+findById(id: int) DomainModel
+remove(id: int)
}
class DataStore {
+save(entity)
+load(id)
+delete(id)
}
class Client
ConcreteRepository ..|> Repository : implements
ConcreteRepository --> DataStore : uses
Client --> Repository : uses
3. Java 实现示例
以下是一个简单的用户管理的仓储模式示例,使用内存存储模拟数据源。
3.1 领域模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class User { private int id; private String name; public User (int id, String name) { this .id = id; this .name = name; } public int getId () { return id; } public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "User{id=" + id + ", name='" + name + "'}" ; } }
3.2 仓储接口
1 2 3 4 5 6 public interface UserRepository { void add (User user) ; User findById (int id) ; void remove (int id) ; }
3.3 具体仓储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class InMemoryUserRepository implements UserRepository { private Map<Integer, User> store = new HashMap <>(); @Override public void add (User user) { store.put(user.getId(), user); } @Override public User findById (int id) { return store.get(id); } @Override public void remove (int id) { store.remove(id); } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Main { public static void main (String[] args) { UserRepository repository = new InMemoryUserRepository (); User user1 = new User (1 , "Alice" ); User user2 = new User (2 , "Bob" ); repository.add(user1); repository.add(user2); User found = repository.findById(1 ); System.out.println("Found: " + found); repository.remove(2 ); System.out.println("After removal, find Bob: " + repository.findById(2 )); } }
3.5 扩展:数据库仓储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class DatabaseUserRepository implements UserRepository { private DataStore database; public DatabaseUserRepository (DataStore database) { this .database = database; } @Override public void add (User user) { database.save(user); } @Override public User findById (int id) { return (User) database.load(id); } @Override public void remove (int id) { database.delete(id); } }
4. 工作原理
客户端 通过仓储接口(UserRepository
)操作数据。
具体仓储(如
InMemoryUserRepository
)实现接口,封装数据访问逻辑。
底层数据存储(如内存或数据库)执行实际操作。
5. 优点
解耦 :业务逻辑不依赖具体数据源。
可测试性 :易于 mock 仓储进行测试。
一致性 :提供类似集合的统一接口。
6. 缺点
额外层 :增加抽象层,可能提高复杂度。
实现成本 :每个实体需定义仓储接口和实现。
性能 :抽象可能掩盖底层优化。
7. 与 DAO 模式的对比
目的
封装数据访问,提供集合接口
数据访问对象,直接操作数据
抽象级别
更高(业务导向)
较低(数据导向)
接口风格
类似集合(如 add、find)
数据库操作(如 CRUD)
8. 实际应用场景
Spring Data :JPA 仓储接口。
DDD(领域驱动设计) :仓储管理聚合根。
测试 :mock 数据访问层。
9. 源码中的例子(Spring Data)
1 2 3 4 5 import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepository <User, Integer> { }
说明 :Spring Data 提供仓储接口,自动生成实现。
10. 总结
仓储模式 通过接口封装数据访问,解耦业务与存储。
Java 实现 支持内存、数据库等多种存储方式。
UML 图 展示了仓储与数据源的关系。
如果需要更复杂示例(如带查询方法)或调整 UML,请告诉我!
服务定位器(Service
Locator)
服务定位器模式(Service Locator
Pattern)是一种设计模式,用于通过一个中央服务定位器(Service
Locator)来查找和获取服务或依赖,而不是直接在客户端中硬编码或手动创建。它是一种替代依赖注入(Dependency
Injection)的服务获取方式,旨在解耦客户端与具体服务的实现。
以下是用 Java
实现服务定位器模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 服务定位器模式的定义
核心思想 :通过服务定位器集中管理和提供服务实例,客户端只需知道服务接口和定位器。
目的 :
适用场景 :
服务实例创建复杂或需要缓存。
客户端需动态获取服务。
不想使用依赖注入框架。
2. 服务定位器模式的结构
服务接口(Service
Interface) :定义服务的契约。
具体服务(Concrete Service) :实现服务接口。
服务定位器(Service
Locator) :管理服务实例,提供查找方法。
客户端(Client) :通过定位器获取服务并使用。
Mermaid UML 图
classDiagram
class Service {
<<interface>>
+doSomething()
}
class ConcreteServiceA {
+doSomething()
}
class ConcreteServiceB {
+doSomething()
}
class ServiceLocator {
-services: Map<String, Service>
+getService(name: String) Service
}
class Client
ConcreteServiceA ..|> Service : implements
ConcreteServiceB ..|> Service : implements
ServiceLocator --> Service : provides
Client --> ServiceLocator : uses
Client --> Service : uses
3. Java 实现示例
以下是一个日志服务的服务定位器示例,客户端通过定位器获取不同日志服务。
3.1 服务接口
1 2 3 4 public interface Logger { void log (String message) ; }
3.2 具体服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ConsoleLogger implements Logger { @Override public void log (String message) { System.out.println("Console: " + message); } } public class FileLogger implements Logger { @Override public void log (String message) { System.out.println("File: " + message); } }
3.3 服务定位器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class ServiceLocator { private static final Map<String, Logger> services = new HashMap <>(); static { services.put("console" , new ConsoleLogger ()); services.put("file" , new FileLogger ()); } public static Logger getLogger (String name) { Logger logger = services.get(name); if (logger == null ) { throw new IllegalArgumentException ("No logger found for: " + name); } return logger; } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 public class Main { public static void main (String[] args) { Logger consoleLogger = ServiceLocator.getLogger("console" ); consoleLogger.log("Hello from console" ); Logger fileLogger = ServiceLocator.getLogger("file" ); fileLogger.log("Hello from file" ); } }
4. 工作原理
服务定位器 初始化时注册服务实例(静态或动态)。
客户端 通过定位器请求服务(getLogger
),只需提供服务标识。
定位器返回服务实例,客户端调用服务方法。
5. 优点
解耦 :客户端不直接依赖服务实现。
集中管理 :服务实例在定位器中统一配置。
简单性 :无需复杂框架即可实现。
6. 缺点
隐式依赖 :客户端依赖定位器,依赖关系不显式。
全局状态 :静态定位器可能导致单例问题。
测试性差 :相比依赖注入,难以 mock 服务。
7. 与依赖注入的对比
依赖获取
客户端主动请求
外部注入
控制权
客户端控制
注入器控制
耦合
依赖定位器
依赖接口
测试性
较差(需 mock 定位器)
较高(易 mock 依赖)
8. 实际应用场景
JNDI :Java 的命名和目录接口。
日志框架 :如 SLF4J 的
LoggerFactory
。
遗留系统 :集中管理服务实例。
9. 源码中的例子
Java 中的 javax.naming.InitialContext
(JNDI):
1 2 3 4 5 6 7 8 import javax.naming.*;public class Example { public static void main (String[] args) throws NamingException { InitialContext context = new InitialContext (); Object service = context.lookup("java:comp/env/myService" ); } }
10. 总结
服务定位器模式 通过集中定位器提供服务访问,解耦客户端与实现。
Java 实现 依赖静态或动态注册,简单但隐式。
UML 图 展示了定位器与服务的关系。
如果需要动态注册示例或调整 UML,请告诉我!
事件溯源(Event
Sourcing)
事件溯源(Event
Sourcing)是一种架构模式,主要用于数据存储和状态管理。它不同于传统的
CRUD(创建、读取、更新、删除)方式,而是通过记录系统中发生的所有事件(Event)来构建和追踪应用程序状态。事件溯源的核心思想是将状态变化作为事件序列存储,而不是直接存储当前状态。
以下是用 Java
实现事件溯源模式的详细讲解,包括定义、结构、代码示例及其优缺点。
1. 事件溯源的定义
核心思想 :将应用程序的状态变化记录为一系列不可变的事件,通过回放事件重建当前状态。
目的 :
提供完整的历史记录。
支持状态重建和审计。
增强系统的可扩展性和一致性。
适用场景 :
需要审计或回溯(如金融系统)。
事件驱动架构(EDA)。
分布式系统(如微服务)。
2. 事件溯源的结构
事件(Event) :表示状态变化的不可变记录。
事件存储(Event
Store) :持久化事件序列的存储。
聚合(Aggregate) :业务实体,应用事件重建状态。
事件处理器(Event
Handler) :处理事件并更新聚合状态。
客户端(Client) :触发事件并查询状态。
Mermaid UML 图
classDiagram
class Event {
-id: String
-type: String
-data: Object
+getId() String
+getType() String
+getData() Object
}
class EventStore {
+append(event: Event)
+getEvents(aggregateId: String) List<Event>
}
class Aggregate {
-id: String
-state: State
+apply(Event)
+getState() State
}
class EventHandler {
+handle(Event, Aggregate)
}
class Client
EventStore --> Event : stores
Aggregate --> Event : applies
EventHandler --> Event : processes
EventHandler --> Aggregate : updates
Client --> EventStore : saves to
Client --> Aggregate : queries
3. Java 实现示例
以下是一个银行账户的事件溯源示例,记录存款和取款事件。
3.1 事件类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 abstract class AccountEvent { private final String accountId; private final long timestamp; public AccountEvent (String accountId) { this .accountId = accountId; this .timestamp = System.currentTimeMillis(); } public String getAccountId () { return accountId; } public long getTimestamp () { return timestamp; } } class DepositEvent extends AccountEvent { private final double amount; public DepositEvent (String accountId, double amount) { super (accountId); this .amount = amount; } public double getAmount () { return amount; } } class WithdrawalEvent extends AccountEvent { private final double amount; public WithdrawalEvent (String accountId, double amount) { super (accountId); this .amount = amount; } public double getAmount () { return amount; } }
3.2 事件存储
1 2 3 4 5 6 7 8 9 10 11 12 public class EventStore { private Map<String, List<AccountEvent>> events = new HashMap <>(); public void append (AccountEvent event) { events.computeIfAbsent(event.getAccountId(), k -> new ArrayList <>()).add(event); } public List<AccountEvent> getEvents (String accountId) { return events.getOrDefault(accountId, new ArrayList <>()); } }
3.3 聚合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Account { private String id; private double balance; public Account (String id) { this .id = id; this .balance = 0 ; } public void apply (AccountEvent event) { if (event instanceof DepositEvent) { balance += ((DepositEvent) event).getAmount(); } else if (event instanceof WithdrawalEvent) { balance -= ((WithdrawalEvent) event).getAmount(); } } public double getBalance () { return balance; } public String getId () { return id; } public static Account rebuild (String id, List<AccountEvent> events) { Account account = new Account (id); for (AccountEvent event : events) { account.apply(event); } return account; } }
3.4 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Main { public static void main (String[] args) { EventStore store = new EventStore (); String accountId = "acc1" ; store.append(new DepositEvent (accountId, 100.0 )); store.append(new DepositEvent (accountId, 50.0 )); store.append(new WithdrawalEvent (accountId, 30.0 )); Account account = Account.rebuild(accountId, store.getEvents(accountId)); System.out.println("Account balance: " + account.getBalance()); } }
4. 工作原理
客户端 触发事件(如存款),存储到事件存储。
事件存储保存不可变的事件序列。
需要状态时,聚合通过回放事件(apply
)重建当前状态。
5. 优点
审计性 :完整事件历史,便于追踪和调试。
灵活性 :可重建任意历史状态。
一致性 :事件序列保证数据完整性。
6. 缺点
存储开销 :事件量大时占用空间多。
性能 :状态重建需回放所有事件,效率低。
复杂性 :实现和维护较复杂。
7. 与传统状态存储对比
存储内容
事件序列
当前状态
状态获取
回放事件重建
直接读取
历史记录
完整
需额外实现
8. 实际应用场景
银行系统 :记录交易历史。
电商 :订单状态追踪。
CQRS :与命令查询职责分离结合。
9. 源码中的例子
Java 中无直接内置实现,但类似概念见于日志框架: 1 2 3 Logger logger = Logger.getLogger("app" );logger.info("Deposit: 100" );
10. 总结
事件溯源 通过事件序列管理状态,支持审计和重建。
Java 实现 依赖事件类和存储,回放重建聚合。
UML 图 展示了事件与聚合的关系。
如果需要更复杂示例(如快照优化)或调整 UML,请告诉我!