长长长文预警,建议同学们可以分模块阅读~ 这篇文章,我们将学习 23 种常见的模式软件设计模式,用举例子和下定义的方式更好的理解和吸收他们,运用于编程实践中。
具体我们分为三类学习:
- 创建型模式
创建型模式是为了解耦对象的创建和使用,也就是说他们提供了灵活的对象创建机制,围绕如何创建对象展开
- 工厂和抽象工厂模式隐藏具体的类实例化逻辑
- 原型模式通过克隆原有对象实现创建
- 建造者模式分步构建复杂对象,提供清晰的构建流程
- 结构型模式
结构型模式是为了组合类或者对象,以形成更大的结构,同时保留系统的可拓展性和组件的可复用性。核心是如何组织类和对象的结构
- 行为型模式
行为型模式的核心目的是管理对象间的协作和职责分配,提供系统的灵活性和可维护性,围绕如对象间如何通信展开
下面的例子,我们用 java 作为面向对象编程的语言做演示。本人才疏学浅,新手上路,请多多指教。
创建型模式
-
工厂模式:****
TCL 有惠州工厂和广州工厂,其中惠州工厂主要生产 CRT 电视机,广州工厂主要生产 LCD 电视机,请设计其生产管理系统。
- 模式名称与定义
名称:工厂方法模式(Factory Method Pattern) 定义:定义一个创建对象的接口,但让子类决定实例化哪个类。工厂方法使类的实例化延迟到子类。
- 应用场景
- 需要创建不同产品的对象
- 系统需要独立于产品的创建过程
- 需要灵活扩展新的产品类型
- 当创建逻辑需要封装在特定工厂中时
- 核心类结构
classDiagram
direction BT
class TV {
<<interface>>
+display()
}
class CRTTV {
+display()
}
class LCDTV {
+display()
}
CRTTV ..|> TV
LCDTV ..|> TV
class TVFactory {
<<interface>>
+createTV() TV
}
class HuizhouFactory {
+createTV() TV
}
class GuangzhouFactory {
+createTV() TV
}
HuizhouFactory ..|> TVFactory
GuangzhouFactory ..|> TVFactory
HuizhouFactory --> CRTTV : creates
GuangzhouFactory --> LCDTV : creates
- Java代码实现
自顶向下的写代码,先知道怎么用,然后再去实现具体的接口和类
使用流程: 创建工厂 - 工厂生产产品 - 使用产品
产品和工厂都有各自的接口,具体的产品和具体的工厂分别去实现对应接口。创建工厂的时候创建相应的工厂即可,对应的产品生产逻辑已经被封装在具体工厂类内部。
// 测试类
public class FactoryPatternDemo {
public static void main(String[] args) {
TVFactory hzFactory = new HuizhouFactory();
TV tv1 = hzFactory.createTV();
tv1.display(); // 惠州工厂生产的CRT电视机
TVFactory gzFactory = new GuangzhouFactory();
TV tv2 = gzFactory.createTV();
tv2.display(); // 广州工厂生产的LCD电视机
}
}
// 产品接口
interface TV {
void display();
}
// 具体产品
class CRTTV implements TV {
@Override
public void display() {
System.out.println("惠州工厂生产的CRT电视机");
}
}
class LCDTV implements TV {
@Override
public void display() {
System.out.println("广州工厂生产的LCD电视机");
}
}
// 工厂接口
interface TVFactory {
TV createTV();
}
// 具体工厂
class HuizhouFactory implements TVFactory {
@Override
public TV createTV() {
return new CRTTV();
}
}
class GuangzhouFactory implements TVFactory {
@Override
public TV createTV() {
return new LCDTV();
}
}
- 实现效果
- 解耦 生产系统:将产品创建与使用分离
- 扩展性强:新增工厂(如深圳工厂)只需实现工厂接口
- 符合 开闭原则:新增产品类型无需修改现有代码
- 统一管理:所有工厂遵循相同的生产接口
- 多态特性:客户端通过工厂接口操作,无需关心具体实现
扩展建议:
- 可以添加
TVType枚举来支持更多产品类型 - 可以结合抽象工厂模式处理配件生产
- 可以添加质量检测等扩展方法到工厂接口
- 可以使用单例模式确保工厂实例唯一性
这种设计使TCL可以轻松扩展新的生产基地(如新增武汉工厂)或新的产品类型(如OLED电视),同时保持系统架构的稳定性和可维护性。
-
抽象工厂:
TCL 有惠州工厂和广州工厂,主要生产不同类型的电视机和电脑,其中惠州工厂主要生产CRT电视机和笔记本电脑,广州工厂主要生产 LCD 电视机和台式电脑,请设计其生产管理系统。
- 名称与定义
抽象工厂模式(Abstract Factory Pattern): 提供接口用于创建相关或依赖对象的家族,而不需要明确指定具体类
- 应用场景
- 需要创建产品族(电视机+电脑的组合)
- 系统需要独立于产品的创建、组合和表示方式
- 需要保证同一工厂生产的产品兼容性
- 存在多个产品等级结构(显示设备/计算设备)
- 核心类结构
classDiagram
class AbstractFactory {
<<interface>>
+createTV() TV
+createComputer() Computer
}
class HuizhouFactory {
+createTV() TV
+createComputer() Computer
}
class GuangzhouFactory {
+createTV() TV
+createComputer() Computer
}
class TV {
<<interface>>
+display()
}
class CRT {
+display()
}
class LCD {
+display()
}
class Computer {
<<interface>>
+compute()
}
class Laptop {
+compute()
}
class Desktop {
+compute()
}
AbstractFactory <|.. HuizhouFactory
AbstractFactory <|.. GuangzhouFactory
TV <|.. CRT
TV <|.. LCD
Computer <|.. Laptop
Computer <|.. Desktop
HuizhouFactory --> CRT
HuizhouFactory --> Laptop
GuangzhouFactory --> LCD
GuangzhouFactory --> Desktop
- 代码实现
// 客户端使用
public class Client {
public static void main(String[] args) {
// 生产惠州产品
AbstractFactory hzFactory = new HuizhouFactory();
hzFactory.createTV().display();
hzFactory.createComputer().compute();
// 生产广州产品
AbstractFactory gzFactory = new GuangzhouFactory();
gzFactory.createTV().display();
gzFactory.createComputer().compute();
}
}
// 抽象产品接口
interface TV {
void display();
}
interface Computer {
void compute();
}
// 具体产品实现
class CRT implements TV {
public void display() {
System.out.println("CRT电视显示");
}
}
class LCD implements TV {
public void display() {
System.out.println("LCD电视显示");
}
}
class Laptop implements Computer {
public void compute() {
System.out.println("笔记本电脑计算");
}
}
class Desktop implements Computer {
public void compute() {
System.out.println("台式电脑计算");
}
}
// 抽象工厂
interface AbstractFactory {
TV createTV();
Computer createComputer();
}
// 具体工厂
class HuizhouFactory implements AbstractFactory {
public TV createTV() {
return new CRT();
}
public Computer createComputer() {
return new Laptop();
}
}
class GuangzhouFactory implements AbstractFactory {
public TV createTV() {
return new LCD();
}
public Computer createComputer() {
return new Desktop();
}
}
优势:
- 保证产品族的一致性(惠州工厂只生产CRT+笔记本,广州工厂只生产LCD+台式机)
- 新增产品族容易(增加新工厂即可)
- 客户端与具体产品解耦
- 符合开闭原则(扩展开放,修改关闭)
扩展:
- 可通过配置文件动态选择工厂
- 增加新产品类型(如显示器)时需修改所有工厂接口
- 可结合单例模式管理工厂实例
工厂模式和抽象工厂模式
工厂模式关注的是一个方法的不同实现逻辑,比如电视的不同种类(对应不同的生产方式) 。工厂模式的抽象类声明一个创建单一对象的接口。
抽象工厂模式关注一组方法的不同实现逻辑的组合,比如电视和遥控器的组合。其抽象类声明的是多个对象的接口。
-
原型模式:
某公司需要一个图形工具箱,提供圆形、长方形和正方形的绘制功能,请为其设计该图形工具箱系统。
原型模式的重在克隆,核心类是一个原型管理器,这里是 Tools,调用原型的时候返回的是各个原型的克隆,所以只需要实例化一次。因为需要返回克隆,所以所有原型类需要从 Cloneable 上继承而来。
- 名称与定义
原型模式(Prototype Pattern) 是一种创建型设计模式,通过复制现有对象(原型)来生成新对象,而非通过 new 创建。这种方式避免了重复初始化带来的性能损耗,特别适用于创建成本较高的对象。
- 应用场景
- 图形工具箱场景:需要频繁创建圆形、矩形、正方形等图形对象,且每个图形初始化可能涉及复杂计算或资源加载。
- 优势:通过预定义原型对象,直接克隆生成新对象,提升性能;支持动态添加新图形类型,符合开闭原则。
- 核心类结构图
classDiagram
class Shape {
<<interface>>
+clone(): Shape
+draw(): void
}
class Circle {
-radius: int
+clone(): Shape
+draw(): void
}
class Rectangle {
-width: int
-height: int
+clone(): Shape
+draw(): void
}
class Square {
-side: int
+clone(): Shape
+draw(): void
}
class GraphicTool {
-prototypes: Map<String, Shape>
+addPrototype(key: String, shape: Shape)
+createShape(key: String): Shape
}
Shape <|.. Circle
Shape <|.. Rectangle
Shape <|.. Square
GraphicTool --> Shape : 依赖原型对象
- 代码实现
public class Client {
public static void main(String[] args) {
// 初始化原型对象(仅一次)
GraphicTool tool = new GraphicTool();
tool.addPrototype("circle", new Circle(10));
tool.addPrototype("rect", new Rectangle(20, 30));
// 通过克隆生成新对象(无需重复初始化)
Shape circle1 = tool.createShape("circle");
circle1.draw(); // 输出:绘制圆形,半径:10
Shape rect1 = tool.createShape("rect");
rect1.draw(); // 输出:绘制矩形,尺寸:20x30
}
}
// 1. 抽象原型接口
interface Shape extends Cloneable {
Shape clone();
void draw();
}
// 2. 具体原型类
class Circle implements Shape {
private int radius;
public Circle(int radius) {
this.radius = radius;
System.out.println("初始化圆形(复杂计算)");
}
@Override
public Shape clone() {
return new Circle(this.radius); // 通过构造器实现深拷贝
}
@Override
public void draw() {
System.out.println("绘制圆形,半径:" + radius);
}
}
class Rectangle implements Shape {
private int width;
private int height;
public Rectangle(int w, int h) {
this.width = w;
this.height = h;
System.out.println("初始化矩形(耗时操作)");
}
@Override
public Shape clone() {
return new Rectangle(width, height);
}
@Override
public void draw() {
System.out.println("绘制矩形,尺寸:" + width + "x" + height);
}
}
// 3. 原型管理器(客户端)
class GraphicTool {
private Map<String, Shape> prototypes = new HashMap<>();
public void addPrototype(String key, Shape shape) {
prototypes.put(key, shape);
}
public Shape createShape(String key) {
Shape prototype = prototypes.get(key);
return prototype != null ? prototype.clone() : null;
}
}
- 实现效果
- 性能提升:避免重复执行耗时的初始化操作(如示例中的
System.out.println模拟的复杂逻辑)。 - 动态扩展性:新增图形(如
Square)只需添加新原型类并注册到管理器,无需修改现有代码。 - 对象独立性:通过构造器复制确保克隆对象与原型的属性隔离(深拷贝),避免副作用。
总结
原型模式在图形工具箱中完美解决了高频创建相似对象时的性能问题,同时保持了系统的灵活性和可维护性。
-
建造者模式:
西式快餐通常由食品和饮料组成,如麦当劳由汉堡和雪碧组成,肯德基由炸鸡和可乐组成,请设计其生产管理系统。
- 名称与定义
建造者模式(Builder Pattern):
- 属于创建型设计模式
- 将复杂对象的构造与其表示分离,使得同样的构建过程可以创建不同的表示
- 特别适用于需要分步骤创建复杂对象且需要灵活组合的场景
- 应用场景
- 西式快餐套餐系统需要灵活组合不同食品和饮料
- 需要保证套餐组合的完整性(必须包含主食和饮品)
- 需要支持未来扩展新的套餐类型
- 需要隔离复杂对象的创建代码和使用代码
- 核心类结构
classDiagram
class Meal {
-String food
-String drink
+showMeal() void
}
class MealBuilder {
<<interface>>
+buildFood()*
+buildDrink()*
+getMeal()* Meal
}
class McDonaldMealBuilder {
+buildFood()
+buildDrink()
+getMeal()
}
class KFCBuilder {
+buildFood()
+buildDrink()
+getMeal()
}
class Director {
-MealBuilder builder
+construct() Meal
}
MealBuilder <|.. McDonaldMealBuilder
MealBuilder <|.. KFCBuilder
Director o--> MealBuilder
MealBuilder ..> Meal
- 代码实现
director 封装的是调用各个 builder 获取内容的过程
Builder 类接口是各个 builder 实现的声明,当然具体需要哪些 Builder 是由 产品类本身决定的
具体的 builder 类依照 Builder 类接口实现各个类,然后借由 director 调用并输出
// 客户端使用
public class FastFoodSystem {
public static void main(String[] args) {
// 创建麦当劳套餐
MealBuilder mcBuilder = new McDonaldMealBuilder();
Director director = new Director(mcBuilder);
Meal mcMeal = director.construct();
mcMeal.showMeal();
// 创建KFC套餐
MealBuilder kfcBuilder = new KFCBuilder();
director = new Director(kfcBuilder);
Meal kfcMeal = director.construct();
kfcMeal.showMeal();
}
}
// 产品类
class Meal {
private String food;
private String drink;
public void setFood(String food) {
this.food = food;
}
public void setDrink(String drink) {
this.drink = drink;
}
public void showMeal() {
System.out.println("套餐包含:" + food + " + " + drink);
}
}
// 抽象建造者
interface MealBuilder {
void buildFood();
void buildDrink();
Meal getMeal();
}
// 具体建造者A
class McDonaldMealBuilder implements MealBuilder {
private Meal meal = new Meal();
@Override
public void buildFood() {
meal.setFood("巨无霸汉堡");
}
@Override
public void buildDrink() {
meal.setDrink("雪碧");
}
@Override
public Meal getMeal() {
return meal;
}
}
// 具体建造者B
class KFCBuilder implements MealBuilder {
private Meal meal = new Meal();
@Override
public void buildFood() {
meal.setFood("黄金炸鸡");
}
@Override
public void buildDrink() {
meal.setDrink("可口可乐");
}
@Override
public Meal getMeal() {
return meal;
}
}
// 指挥者
class Director {
private MealBuilder builder;
public Director(MealBuilder builder) {
this.builder = builder;
}
public Meal construct() {
builder.buildFood();
builder.buildDrink();
return builder.getMeal();
}
}
- 实现效果
套餐包含:巨无霸汉堡 + 雪碧
套餐包含:黄金炸鸡 + 可口可乐
模式优势:
- 封装了套餐的创建过程,客户端无需知道具体组合细节 ( builder 逻辑封装在具体的 builder 中,调用顺序过程封装在 director 类中)
- 建造者独立,易于扩展新的套餐类型(如新增必胜客建造者新增一个 builder 具体类即可)
- 可以更精细地控制创建过程(通过 director 实现)(如增加校验逻辑)
- 符合单一职责原则和开闭原则
- 支持套餐组合的标准化(必须包含主食和饮品)
扩展建议:
- 可以添加
validate()方法验证套餐完整性 - 可增加
setPackageType()方法支持不同规格的套餐 - 可以使用链式调用改进建造者接口
- 可以结合工厂模式创建不同类型的建造者
结构性模式
-
外观模式:
电脑开机包括 CPU 启动、 内存 自检、硬盘读取和 OS 装入四个步骤,请设计该开机系统。
- 名称与定义
名称:外观模式(Facade Pattern) 定义:为子系统中的一组接口提供一个一致的统一高层接口,这个接口使得这一子系统更加容易使用
- 应用场景
适用于需要简化复杂系统操作流程的场景:
- 当需要为复杂的子系统提供简单入口时
- 当系统存在多层依赖关系需要解耦时
- 需要为遗留系统提供更清晰的访问接口时
- 核心类结构图
classDiagram
class ComputerBootFacade {
- cpu: CPU
- memory: Memory
- hardDrive: HardDrive
- osLoader: OSLoader
+ startComputer()
}
class CPU {
+ powerOn()
}
class Memory {
+ selfCheck()
}
class HardDrive {
+ readData()
}
class OSLoader {
+ loadOS()
}
ComputerBootFacade --> CPU
ComputerBootFacade --> Memory
ComputerBootFacade --> HardDrive
ComputerBootFacade --> OSLoader
- 代码实现
将多个类的调用封装到一个外观类中,然后只需要调用外观类。
// 客户端调用
public class Client {
public static void main(String[] args) {
ComputerBootFacade computer = new ComputerBootFacade();
computer.startComputer();
}
}
// 子系统类
class CPU {
public void powerOn() {
System.out.println("CPU启动成功");
}
}
class Memory {
public void selfCheck() {
System.out.println("内存自检完成");
}
}
class HardDrive {
public void readData() {
System.out.println("硬盘数据读取完毕");
}
}
class OSLoader {
public void loadOS() {
System.out.println("操作系统载入完成");
}
}
// 外观类
class ComputerBootFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
private OSLoader osLoader;
public ComputerBootFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
this.osLoader = new OSLoader();
}
public void startComputer() {
System.out.println("开始启动计算机系统");
cpu.powerOn();
memory.selfCheck();
hardDrive.readData();
osLoader.loadOS();
System.out.println("计算机启动完成");
}
}
- 实现效果
当执行程序时,控制台输出:
开始启动计算机系统
CPU启动成功
内存自检完成
硬盘数据读取完毕
操作系统载入完成
计算机启动完成
优势:
- 将复杂的启动流程封装在单一接口中
- 客户端只需与外观类交互,无需了解子系统细节
- 降低系统耦合度,各子系统可独立修改
- 提供统一入口,符合最少知识原则
扩展性:
- 新增启动步骤时只需修改外观类
- 可创建不同外观类实现不同启动策略(如快速启动模式)
- 子系统组件可独立升级不影响客户端代码
-
适配器模式:
现有一个mp3播放器和一个mp4播放器,为了简便代码实现,我们希望用mp3播放器来播放mp4文件,请设计该系统。
- 名称与定义
适配器模式 ( Adapter Pattern ) 定义:将一个类的接口转换成客户端希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。
- 应用场景
- 场景:已有
Mp3Player和Mp4Player两个播放器,但希望复用Mp3Player的接口来播放MP4文件。 - 痛点:
Mp3Player无法直接调用Mp4Player的方法(接口不兼容)。 - 解决方案:通过适配器将
Mp4Player的功能“伪装”成Mp3Player的接口。
- 核心类图
classDiagram
class Mp3Player {
<<interface>>
+playMp3(String fileName)
}
class Mp3PlayerImpl {
+playMp3(String fileName)
}
class Mp4Player {
<<interface>>
+playMp4(String fileName)
}
class Mp4PlayerImpl {
+playMp4(String fileName)
}
class Mp4ToMp3Adapter {
-Mp4Player mp4Player
+Mp4ToMp3Adapter(Mp4Player mp4Player)
+playMp3(String fileName)
}
Mp3PlayerImpl ..|> Mp3Player
Mp4PlayerImpl ..|> Mp4Player
Mp4ToMp3Adapter ..|> Mp3Player
Mp4ToMp3Adapter --> Mp4Player : 适配对象
- 代码实现
通过 adapter 包装,让旧的接口实现新接口的逻辑。有点 AOP 编程的意味。在这道题的语境中,在实际调用 mp3 之前用 adapter 封装目标类,通过 AOP 重写的 playMp3 ,使之能够直接调用 mp3 处理 mp4 相关了逻辑。
// 客户端代码
public class Client {
public static void main(String[] args) {
// 原生MP3播放器
Mp3Player mp3Player = new Mp3PlayerImpl();
mp3Player.playMp3("music.mp3"); // 输出: [MP3] Playing: music.mp3
// 通过适配器播放MP4文件
Mp4Player mp4Player = new Mp4PlayerImpl();
Mp3Player adapter = new Mp4ToMp3Adapter(mp4Player);
adapter.playMp3("video.mp4"); // 输出: [MP4] Playing: video.mp4
}
}
// 1. 定义MP3播放器接口
public interface Mp3Player {
void playMp3(String fileName);
}
// 2. 具体MP3播放器实现
public class Mp3PlayerImpl implements Mp3Player {
@Override
public void playMp3(String fileName) {
System.out.println("[MP3] Playing: " + fileName);
}
}
// 3. 定义MP4播放器接口
public interface Mp4Player {
void playMp4(String fileName);
}
// 4. 具体MP4播放器实现
public class Mp4PlayerImpl implements Mp4Player {
@Override
public void playMp4(String fileName) {
System.out.println("[MP4] Playing: " + fileName);
}
}
// 5. 适配器类(核心)
public class Mp4ToMp3Adapter implements Mp3Player {
private final Mp4Player mp4Player;
public Mp4ToMp3Adapter(Mp4Player mp4Player) {
this.mp4Player = mp4Player;
}
@Override
public void playMp3(String fileName) {
// 将MP3播放请求转发给MP4播放器
mp4Player.playMp4(fileName);
}
}
- 实现效果
- 功能兼容:
Mp3Player接口通过适配器间接调用Mp4Player的功能,实现了接口的统一。 - 代码复用:无需修改
Mp3Player和Mp4Player的原有代码,符合开闭原则。 - 灵活性:未来可扩展支持其他格式(如AVI)只需新增适配器类。
关键点:适配器模式通过“包装”被适配对象(Mp4Player),将其能力映射到目标接口(Mp3Player),是解决接口不兼容问题的经典方案。
-
组合模式:
大学包含多个学院,学院又包含多个学科专业,请设计该系统。
-
名称:组合模式(Composite Pattern) 定义:将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性
-
应用场景:
- 需要表示对象的整体与部分的层次结构
- 希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象
- 树形菜单、文件目录结构等具有层级关系的场景
-
核心类结构:
classDiagram
class Component {
<<abstract>>
+show_info()
}
class University {
-name: String
+add(component: Component)
+remove(component: Component)
+show_info()
}
class Faculty {
-name: String
+add(component: Component)
+remove(component: Component)
+show_info()
}
class Major {
-name: String
+show_info()
}
Component <|-- University
Component <|-- Faculty
Component <|-- Major
University o-- Component
Faculty o-- Component
- 代码实现:
强调层次结构,通过类之间的嵌套实现层次结构的表达。
抽象类规定了每个节点类的基本接口,具体类可调用传入的其他具体类进行嵌套。
import java.util.ArrayList;
import java.util.List;
// 客户端使用
public class CompositePatternDemo {
public static void main(String[] args) {
University university = new University("清华大学");
Faculty csFaculty = new Faculty("计算机学院");
Faculty eeFaculty = new Faculty("电子工程学院");
csFaculty.add(new Major("软件工程"));
csFaculty.add(new Major("人工智能"));
eeFaculty.add(new Major("电子信息工程"));
eeFaculty.add(new Major("微电子学"));
university.add(csFaculty);
university.add(eeFaculty);
university.showInfo("");
}
}
// 抽象组件
abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void showInfo(String prefix);
}
// 复合节点:大学
class University extends Component {
private List<Component> faculties = new ArrayList<>();
public University(String name) {
super(name);
}
public void add(Component component) {
faculties.add(component);
}
public void remove(Component component) {
faculties.remove(component);
}
@Override
public void showInfo(String prefix) {
System.out.println("【大学】" + name);
for (int i = 0; i < faculties.size(); i++) {
Component faculty = faculties.get(i);
if (i == faculties.size() - 1) {
faculty.showInfo("└─");
} else {
faculty.showInfo("├─");
}
}
}
}
// 复合节点:学院
class Faculty extends Component {
private List<Component> majors = new ArrayList<>();
public Faculty(String name) {
super(name);
}
public void add(Component component) {
majors.add(component);
}
public void remove(Component component) {
majors.remove(component);
}
@Override
public void showInfo(String prefix) {
System.out.println(prefix + "【学院】" + name);
String childPrefix = prefix.startsWith("├") ? "│ " : " ";
for (Component major : majors) {
major.showInfo(childPrefix + "└─");
}
}
}
// 叶子节点:专业
class Major extends Component {
public Major(String name) {
super(name);
}
@Override
public void showInfo(String prefix) {
System.out.println(prefix + "【专业】" + name);
}
}
- 实现效果:
【大学】清华大学
├─【学院】计算机学院
│ └─【专业】软件工程
│ └─【专业】人工智能
├─【学院】电子工程学院
│ └─【专业】电子信息工程
│ └─【专业】微电子学
关键点:
- 通过统一的Component接口处理所有节点
- 复合节点(大学/学院)可以包含其他组件,形成递归结构
- 叶子节点(专业)是最小组成单元,没有子节点
- 客户端可以一致地处理任意层次的组件
- 展示时自动生成树形结构格式,直观展示层级关系
这种设计可以方便地扩展新的学院类型或专业类型,同时保持结构的清晰性和操作的一致性。例如要新增一个管理学院,只需要创建新的Faculty实例并添加专业即可,不需要修改现有代码。
-
代理模式:
请为房产中介公司设计一套房屋租赁系统。
- 名称与定义 代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。
- 应用场景
- 需要控制对真实对象的访问
- 添加额外功能(带看房、合同审核等)
- 核心类结构
classDiagram
class RentSubject {
<<interface>>
+rent(): void
}
class HouseOwner {
-name: String
+HouseOwner(name: String)
+rent(): void
}
class HouseAgent {
-owner: HouseOwner
-agentFee: int
+HouseAgent(owner: HouseOwner)
+rent(): void
-preService(): void
-postService(): void
}
RentSubject <|.. HouseOwner
RentSubject <|.. HouseAgent
HouseAgent --> HouseOwner
- Java代码实现
真实目标类不直接被操作,而是将方法交由代理类操作,外部实体直接于代理类交互,从而间接调用到目标类的方法。对于目标类而言,提供方法这个行为就被代理类“代为管理”了。
// 客户端使用
public class ProxyPatternDemo {
public static void main(String[] args) {
// 创建真实房主
HouseOwner realOwner = new HouseOwner("王先生");
// 创建代理中介
HouseAgent agent = new HouseAgent(realOwner);
// 通过代理租房
System.out.println("----- 租客开始租房流程 -----");
agent.rent();
}
}
// 1. 租赁接口
interface RentSubject {
void rent();
}
// 2. 真实主体类
class HouseOwner implements RentSubject {
private String name;
public HouseOwner(String name) {
this.name = name;
}
@Override
public void rent() {
System.out.println("[房主 " + name + "] 签订租赁合同,收到租金");
}
}
// 3. 代理类
class HouseAgent implements RentSubject {
private HouseOwner owner;
private int agentFee = 500;
public HouseAgent(HouseOwner owner) {
this.owner = owner;
}
private void preService() {
System.out.println("[中介] 带客户看房,筛选租客资质");
}
private void postService() {
System.out.println("[中介] 收取中介服务费:" + agentFee + "元");
}
@Override
public void rent() {
preService();
owner.rent();
postService();
}
}
- 执行结果
----- 租客开始租房流程 -----
[中介] 带客户看房,筛选租客资质
[房主 王先生] 签订租赁合同,收到租金
[中介] 收取中介服务费:500元
Java实现要点:
- 严格类型定义:通过
implements显式声明接口实现 - 访问控制:使用
private保护代理类的内部方法 - 构造器注入:通过构造函数强制要求代理必须绑定真实房主
- 符合Java规范:遵循驼峰命名法,使用接口定义行为契约
如果需要扩展远程代理或虚拟代理,可以通过添加网络通信或延迟加载机制来实现。
-
桥接模式:
小米和VIVO手机都有直板和翻盖两种机型,请设计一个用小米直板手机打电话的系统。
桥接模式实现小米直板手机打电话系统
- 名称与定义
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。通过组合代替继承,在两个维度(手机类型 x 手机品牌)之间建立连接。
- 应用场景
当存在多个维度的变化(如手机形态和手机品牌),且需要避免使用多层继承带来的类爆炸问题时,适合使用桥接模式。
- 核心类结构图
classDiagram
direction BT
class Phone {
<<abstract>>
-brand: Brand
+Phone(Brand)
+call() void
}
class BarPhone {
+call() void
}
class FoldablePhone {
+call() void
}
class Brand {
<<interface>>
+callImpl() void
}
class Xiaomi {
+callImpl() void
}
class Vivo {
+callImpl() void
}
Phone <|-- BarPhone
Phone <|-- FoldablePhone
Phone o--> Brand
Brand <|.. Xiaomi
Brand <|.. Vivo
- 代码实现
关注的是一个实体的不同维度的内容。
public class Client {
public static void main(String[] args) {
Phone xiaomiBar = new BarPhone(new Xiaomi());
xiaomiBar.call();
}
}
// 输出结果:
// 直板机展开屏幕
// 小米手机执行拨号
// 实现维度接口
interface Brand {
void callImpl();
}
// 具体品牌实现
class Xiaomi implements Brand {
@Override
public void callImpl() {
System.out.println("小米手机执行拨号");
}
}
// 抽象手机类型
abstract class Phone {
protected Brand brand;
public Phone(Brand brand) {
this.brand = brand;
}
public abstract void call();
}
// 具体手机形态
class BarPhone extends Phone {
public BarPhone(Brand brand) {
super(brand);
}
@Override
public void call() {
System.out.println("直板机展开屏幕");
brand.callImpl();
}
}
模式优势
- 维度 解耦:手机形态(直板/翻盖)与品牌(小米/VIVO)独立变化
- 扩展性强:新增品牌只需实现Brand接口,新增形态只需继承Phone类
- 避免类爆炸:N个品牌xM种形态只需N+M个类,而非N*M个组合类
区分桥接模式和组合模式的区别
组合模式: 处理树形关系的 “部分-整体”之间的关系
桥接模式:处理两个平行的类层次之间的关系,将 M * N,简化为 M + N 个类
-
装饰模式:
有一家咖啡店,美式咖啡是5元/杯,意大利咖啡是8元/杯,一份牛奶是2元,一份方糖是1元,请编码计算“1杯美式+1份牛奶+2份方糖”一共多少钱?
装饰模式解决咖啡店价格计算问题
- 名称与定义
装饰模式 ( Decorator Pattern ) 是一种结构型设计模式,允许动态地向对象添加职责。通过将对象包装在装饰器类中,可以在不修改原有类的情况下扩展功能。
- 应用场景
- 动态扩展对象功能:当需要为对象添加灵活的、可插拔的附加功能时。
- 替代 继承:当通过继承会导致类爆炸或无法实现运行时扩展时。
- 组合替代 继承:通过嵌套装饰器实现复杂功能的叠加。
- 核心类结构
classDiagram
class Coffee {
<<abstract>>
+cost() double
}
Coffee <|-- Americano
Coffee <|-- Espresso
Coffee <|-- CondimentDecorator
CondimentDecorator <|-- Milk
CondimentDecorator <|-- Sugar
class Americano {
+cost() double
}
class Espresso {
+cost() double
}
class CondimentDecorator {
<<abstract>>
-coffee: Coffee
+CondimentDecorator(Coffee)
+cost() double
}
class Milk {
+cost() double
}
class Sugar {
+cost() double
}
- 代码实现
// 抽象组件:咖啡
public abstract class Coffee {
public abstract double cost();
}
// 具体组件:美式咖啡
public class Americano extends Coffee {
@Override
public double cost() {
return 5;
}
}
// 具体组件:意式咖啡
public class Espresso extends Coffee {
@Override
public double cost() {
return 8;
}
}
// 抽象装饰器:配料
public abstract class CondimentDecorator extends Coffee {
protected Coffee coffee;
public CondimentDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public abstract double cost();
}
// 具体装饰器:牛奶
public class Milk extends CondimentDecorator {
public Milk(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return 2 + coffee.cost();
}
}
// 具体装饰器:方糖
public class Sugar extends CondimentDecorator {
public Sugar(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return 1 + coffee.cost();
}
}
// 客户端代码
public class CoffeeShop {
public static void main(String[] args) {
Coffee order = new Americano(); // 美式咖啡(5元)
order = new Milk(order); // 加牛奶(+2元)
order = new Sugar(order); // 加第1份方糖(+1元)
order = new Sugar(order); // 加第2份方糖(+1元)
System.out.println("总价格:" + order.cost() + "元"); // 输出:9.0
}
}
- 实现效果
-
代码输出:总价格为 9元(美式5元 + 牛奶2元 + 方糖1元 × 2)。
-
优点:
- 灵活扩展:可动态叠加任意数量和类型的配料。
- 符合 开闭原则:新增咖啡或配料时无需修改现有代码。
- 避免 继承 爆炸:通过组合替代多层继承。
-
装饰过程:
- 创建基础咖啡对象(
Americano)。 - 用
Milk装饰它,添加牛奶价格。 - 用
Sugar装饰两次,每次添加方糖价格。
- 创建基础咖啡对象(
-
享元模式:
请设计共享单车租赁系统,用户提供姓名即可租赁、归还单车。
- 名称和定义
享元模式 (Flyweight Pattern) 通过共享对象来有效支持大量细粒度对象的复用,减少内存开销。将对象状态分为内部状态(不可变)和外部状态(可变)。
- 应用场景
共享单车租赁系统中:
- 单车基础属性(型号、品牌)作为内部状态共享
- 单车动态属性(位置、租赁状态)作为外部状态独立管理
- 避免为每辆单车重复存储固定属性
- 核心类图
classDiagram
class BikeType {
-String model
-String brand
+BikeType(model, brand)
+getModel()
+getBrand()
}
class Bike {
-String serialNumber
-BikeType type
+Bike(serialNumber, type)
+getInfo()
}
class BikeFactory {
-Map<String, BikeType> pool
+getBikeType(model, brand)
}
class RentalSystem {
-Map<User, Bike> rentals
-List<Bike> availableBikes
+rentBike(user, model)
+returnBike(user)
}
BikeType --> Bike : 组合
BikeFactory --> BikeType : 创建
RentalSystem --> Bike : 管理
RentalSystem --> BikeFactory : 使用
- 代码实现
通过一个抽象类管理内部数据以复用,这个类的实例化被注入外部数据,而管理外部数据是由管理类控制的。
// 实现效果
public class Main {
public static void main(String[] args) {
RentalSystem system = new RentalSystem();
system.rentBike("Alice", "A100"); // Alice rented Mobike A100 #1001
system.rentBike("Bob", "E200"); // Bob rented HelloBike E200 #2001
system.returnBike("Alice"); // Alice returned Mobike A100 #1001
system.rentBike("Charlie", "A100");// Charlie rented Mobike A100 #1001
}
}
// 享元对象(内部状态)
class BikeType {
private final String model;
private final String brand;
public BikeType(String model, String brand) {
this.model = model;
this.brand = brand;
}
public String getModel() { return model; }
public String getBrand() { return brand; }
}
// 具体对象(包含外部状态)
class Bike {
private final String serialNumber;
private final BikeType type;
public Bike(String serialNumber, BikeType type) {
this.serialNumber = serialNumber;
this.type = type;
}
public String getInfo() {
return type.getBrand() + " " + type.getModel() + " #" + serialNumber;
}
}
// 享元工厂
class BikeFactory {
private final Map<String, BikeType> pool = new HashMap<>();
public BikeType getBikeType(String model, String brand) {
String key = model + "_" + brand;
if (!pool.containsKey(key)) {
pool.put(key, new BikeType(model, brand));
}
return pool.get(key);
}
}
// 租赁系统(维护外部状态)
class RentalSystem {
private final Map<String, Bike> rentals = new HashMap<>();
private final List<Bike> availableBikes = new ArrayList<>();
private final BikeFactory factory = new BikeFactory();
public RentalSystem() {
// 初始化库存
BikeType type1 = factory.getBikeType("A100", "Mobike");
BikeType type2 = factory.getBikeType("E200", "HelloBike");
availableBikes.add(new Bike("1001", type1));
availableBikes.add(new Bike("1002", type1));
availableBikes.add(new Bike("2001", type2));
}
public void rentBike(String userName, String model) {
Bike bike = availableBikes.stream()
.filter(b -> b.getInfo().contains(model) && !rentals.containsValue(b))
.findFirst()
.orElseThrow(() -> new RuntimeException("No available bike"));
rentals.put(userName, bike);
System.out.println(userName + " rented " + bike.getInfo());
}
public void returnBike(String userName) {
Bike bike = rentals.remove(userName);
if (bike != null) {
System.out.println(userName + " returned " + bike.getInfo());
}
}
}
优势:
- 内存优化:相同型号的单车共享BikeType对象
- 扩展性:新增单车类型不会显著增加内存
- 状态分离:租赁状态由RentalSystem独立管理
- 对象复用:归还后的单车可以重复利用
验证点:
- 相同型号的两次租赁输出共享型号信息
- 归还后的单车可以被其他用户再次租赁
- 工厂类保证同型号单车类型唯一
行为型模式
-
策略模式:
一种双语电子词典,可以用汉语和英语进行单词播放,请设计该播放系统。
好的,以下是根据策略模式设计的双语电子词典播放系统解决方案:
- 模式名称与定义 策略模式(Strategy Pattern) :定义一系列算法族,将每个算法封装起来,使它们可以互相替换,且算法的变化不会影响使用它的客户端。
- 应用场景 适用于需要动态切换单词发音策略的场景(如中英文发音切换),且未来可能扩展其他语种发音功能。
- 核心类 结构图
听起来好像和工厂模式一样,但由类图可以看出他和工厂模式有所不同。
工厂模式是根据接口创建工厂类,然后直接使用工厂类
而策略模式是对一个能够以插件形式添加策略的类,使用不同的策略来达成不同的效果,核心类只有一个
classDiagram
class Dictionary {
-strategy: PronunciationStrategy
+setStrategy(PronunciationStrategy)
+playWord(String)
}
class PronunciationStrategy {
<<interface>>
+play(String)
}
class ChinesePronunciation {
+play(String)
}
class EnglishPronunciation {
+play(String)
}
Dictionary o--> PronunciationStrategy
ChinesePronunciation ..|> PronunciationStrategy
EnglishPronunciation ..|> PronunciationStrategy
- Java代码实现
// 使用示例
public class Client {
public static void main(String[] args) {
Dictionary dict = new Dictionary();
String word = "Hello";
// 播放中文发音
dict.setStrategy(new ChinesePronunciation());
dict.playWord(word); // 输出:播放中文发音:Hello
// 切换英文发音
dict.setStrategy(new EnglishPronunciation());
dict.playWord(word); // 输出:Playing English pronunciation: Hello
}
}
// 策略接口
interface PronunciationStrategy {
void play(String word);
}
// 中文发音策略
class ChinesePronunciation implements PronunciationStrategy {
@Override
public void play(String word) {
System.out.println("播放中文发音:" + word);
}
}
// 英文发音策略
class EnglishPronunciation implements PronunciationStrategy {
@Override
public void play(String word) {
System.out.println("Playing English pronunciation: " + word);
}
}
// 词典上下文
class Dictionary {
private PronunciationStrategy strategy;
public void setStrategy(PronunciationStrategy strategy) {
this.strategy = strategy;
}
public void playWord(String word) {
if (strategy != null) {
strategy.play(word);
} else {
System.out.println("请先选择发音策略");
}
}
}
-
实现效果
- 灵活扩展:新增语种只需实现策略接口(如新增FrenchPronunciation)
- 解耦 明显:发音算法与词典主体分离,符合开闭原则
- 动态切换:运行时通过setStrategy()自由切换发音策略
- 复用性强:不同词典实例可配置不同发音策略
关键设计亮点:将易变的发音行为抽象为独立策略,词典类仅负责维护当前策略和触发播放动作,完美实现关注点分离。
-
模板模式:
不同银行的柜台办事流程基本相同,都包含了取号、办理业务和柜员评价三个环节,但具体操作细节有差异,请设计该业务办理系统。
好的!我将按照要求分步骤解答模板模式在银行柜台系统中的应用:
- 模式名称与定义
模板方法模式:定义一个操作中的算法骨架,将某些步骤延迟到子类实现。该模式使得子类可以不改变算法结构的情况下重新定义某些特定步骤。
- 应用场景
适用于银行柜台系统这种具有固定流程但存在差异化实现的场景:
- 统一流程:取号→办理业务→评价
- 差异化实现:不同银行在取号方式、业务办理规则、评价系统上的不同实现
- 核心类图
说的直白一点,模板模式就是定义好接口,然后去实现。注意是以抽象类的方式定义的接口。
其中流程执行函数是不可重写的,为了保证流程的统一(final)。而其他模式是必须重写的,为了实现差异化的流程节点。
classDiagram
class BankProcessTemplate {
<<abstract>>
+final process()
+abstract takeNumber()
+abstract handleBusiness()
+abstract evaluateService()
}
class ICBCBankProcess {
+takeNumber()
+handleBusiness()
+evaluateService()
}
class CCBBankProcess {
+takeNumber()
+handleBusiness()
+evaluateService()
}
BankProcessTemplate <|-- ICBCBankProcess
BankProcessTemplate <|-- CCBBankProcess
- Java代码实现
// 抽象模板类
abstract class BankProcessTemplate {
// 模板方法(不可重写)
public final void process() {
takeNumber();
handleBusiness();
evaluateService();
}
// 抽象方法由子类实现
public abstract void takeNumber();
public abstract void handleBusiness();
public abstract void evaluateService();
}
// 工商银行实现
class ICBCBankProcess extends BankProcessTemplate {
@Override
public void takeNumber() {
System.out.println("工商银行:刷身份证取号");
}
@Override
public void handleBusiness() {
System.out.println("工商银行:办理对公账户业务");
}
@Override
public void evaluateService() {
System.out.println("工商银行:五星评分系统");
}
}
// 建设银行实现
class CCBBankProcess extends BankProcessTemplate {
@Override
public void takeNumber() {
System.out.println("建设银行:扫码取号");
}
@Override
public void handleBusiness() {
System.out.println("建设银行:办理个人贷款业务");
}
@Override
public void evaluateService() {
System.out.println("建设银行:笑脸评价系统");
}
}
- 实现效果
public class Client {
public static void main(String[] args) {
System.out.println("=== 工商银行流程 ===");
BankProcessTemplate icbc = new ICBCBankProcess();
icbc.process();
System.out.println("\n=== 建设银行流程 ===");
BankProcessTemplate ccb = new CCBBankProcess();
ccb.process();
}
}
/* 输出结果:
=== 工商银行流程 ===
工商银行:刷身份证取号
工商银行:办理对公账户业务
工商银行:五星评分系统
=== 建设银行流程 ===
建设银行:扫码取号
建设银行:办理个人贷款业务
建设银行:笑脸评价系统
*/
模式优势:
- 流程标准化:确保所有银行的3个核心步骤执行顺序一致
- 扩展性强:新增银行只需继承模板类实现具体方法
- 复用性高:将公共流程提升到父类,避免重复代码
- 控制反转:父类控制流程执行,子类只负责具体实现
应用扩展:可以增加钩子方法(hook method)控制流程分支,例如在评价环节前增加if(needEvaluate())判断是否需要评价
-
备忘录模式:
设计一个小游戏存档恢复系统。
- 名称与定义
备忘录模式(Memento Pattern)是一种行为设计模式,允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。核心思想是通过一个备忘录对象来存储另一个对象的内部状态快照。
- 应用场景
适用于需要:
- 提供游戏存档/读档功能
- 实现撤销/重做操作
- 需要保存对象历史状态且不破坏封装性
- 需要外部对象来存储对象状态(如自动保存功能)
- 核心类结构
将一个快照状态再封装为一个 memento。当然这个 momento 是内部实现,不需要暴露使用。使用的时候我们只需要关注 player 本身和一个存档管理器即可。
classDiagram
class Originator {
-state: GameState
+save(): Memento
+restore(Memento): void
}
class Memento {
-state: GameState
+getState(): GameState
}
class Caretaker {
-mementos: List
Memento
+saveMemento(Memento): void
+getMemento(int): Memento
}
Originator --> Memento : creates
Caretaker o-- Memento : contains
- Java代码实现
// 使用示例
public class MementoDemo {
public static void main(String[] args) {
SaveManager saveManager = new SaveManager();
GameCharacter player = new GameCharacter();
// 初始状态
player.setState(new GameState("Forest", 100, 0));
System.out.println("初始状态: " + player.getState());
// 保存第一个存档
saveManager.addSave(player.save());
// 改变状态
player.setState(new GameState("Castle", 75, 150));
System.out.println("战斗后状态: " + player.getState());
// 保存第二个存档
saveManager.addSave(player.save());
// 恢复第一个存档
player.restore(saveManager.getSave(0));
System.out.println("恢复初始存档: " + player.getState());
}
}
// 游戏状态类(需要保存的数据)
class GameState {
private String level;
private int hp;
private int positionX;
public GameState(String level, int hp, int positionX) {
this.level = level;
this.hp = hp;
this.positionX = positionX;
}
@Override
public String toString() {
return "Level: " + level + " | HP: " + hp + " | PositionX: " + positionX;
}
}
// 原发器(需要保存状态的对象)
class GameCharacter {
private GameState state;
public void setState(GameState state) {
this.state = state;
}
public GameState getState() {
return state;
}
public Memento save() {
return new Memento(this.state);
}
public void restore(Memento memento) {
this.state = memento.getState();
}
// 备忘录内部类
class Memento {
private final GameState state;
private Memento(GameState state) {
this.state = new GameState(state.level, state.hp, state.positionX);
}
private GameState getState() {
return state;
}
}
}
// 负责人(存档管理器)
class SaveManager {
private final List<GameCharacter.Memento> saves = new ArrayList<>();
public void addSave(GameCharacter.Memento memento) {
saves.add(memento);
}
public GameCharacter.Memento getSave(int index) {
return saves.get(index);
}
}
- 实现效果
初始状态: Level: Forest | HP: 100 | PositionX: 0
战斗后状态: Level: Castle | HP: 75 | PositionX: 150
恢复初始存档: Level: Forest | HP: 100 | PositionX: 0
优势:
- 状态封装:游戏角色的内部状态存储细节被隐藏
- 时间回退:可以轻松恢复到任意存档点状态
- 职责分离:存档管理逻辑与游戏角色逻辑解耦
- 可扩展性:方便添加自动保存、多存档槽等功能
扩展方向:
- 增加存档时间戳
- 实现存档压缩加密
- 添加存档有效性验证
- 支持云存储功能
- 实现存档回放功能
-
观察者模式:
某站有许多up主,也有许多user用户,用户可以关注up,获取up的更新推送,请设计该消息管理系统。
- 名称与定义
观察者模式(Observer Pattern) 定义对象间的一对多依赖关系,当一个对象(被观察者)状态改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。
- 应用场景
-
场景需求:用户关注UP主,UP主发布新内容时通知所有关注者。
-
适用性
- 需要动态联动更新(如用户订阅机制)。
- 避免依赖对象频繁轮询检查状态变化。
- 核心类结构
classDiagram
class Subject {
<<interface>>
+registerObserver(Observer o)
+removeObserver(Observer o)
+notifyObservers(String message)
}
class UPSubject {
-name: String
-observers: List<Observer>
+postVideo(String videoTitle)
}
class Observer {
<<interface>>
+update(String message)
}
class UserObserver {
-name: String
+update(String message)
}
Subject <|-- UPSubject
Observer <|-- UserObserver
UPSubject o-- Observer : 聚合
- 代码实现
核心代码围绕观察者和被观察者展开。被观察者和观察者实现各自的接口。
被观察者有添加,删除观察者的方法和触发通知的方法。
观察者有监听的函数。
// 使用
public class Main {
public static void main(String[] args) {
// 创建UP主
UPSubject techUP = new UPSubject("科技UP主");
UPSubject foodUP = new UPSubject("美食UP主");
// 创建用户
UserObserver userA = new UserObserver("A");
UserObserver userB = new UserObserver("B");
// 用户关注UP主
techUP.registerObserver(userA);
techUP.registerObserver(userB);
foodUP.registerObserver(userA);
// UP主发布内容
techUP.postVideo("iPhone 15 评测");
foodUP.postVideo("红烧肉做法");
}
}
接口定义
// 主题接口(被观察者)
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers(String message);
}
// 观察者接口
public interface Observer {
void update(String message);
}
具体被观察者(UP主)
public class UPSubject implements Subject {
private final String name;
private final List<Observer> observers = new ArrayList<>();
public UPSubject(String name) {
this.name = name;
}
// 发布新视频时触发通知
public void postVideo(String videoTitle) {
String message = name + "发布了新视频:" + videoTitle;
notifyObservers(message);
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers(String message) {
for (Observer o : observers) {
o.update(message);
}
}
}
具体观察者(用户)
public class UserObserver implements Observer {
private final String name;
public UserObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println("[用户 " + name + "] 收到通知:" + message);
}
}
输出结果
[用户 A] 收到通知:科技UP主发布了新视频:iPhone 15 评测
[用户 B] 收到通知:科技UP主发布了新视频:iPhone 15 评测
[用户 A] 收到通知:美食UP主发布了新视频:红烧肉做法
模式优势
- 松耦合:UP主和用户无直接依赖,通过接口交互。
- 动态订阅:可随时增删观察者。
- 广播通知:一次状态更新可触发所有观察者响应。
-
命令模式:
餐厅服务员接受到顾客订单后,通知厨师制作食品,请设计该餐厅业务处理系统。
- 名称 & 定义
命令模式 ( Command Pattern ) 将请求封装成一个对象,使请求的发送者和接收者解耦,并支持请求的排队、记录日志、撤销/重做等操作。
- 应用场景
- 餐厅订单系统:服务员(调用者)无需知道厨师(接收者)如何烹饪,只需将订单(命令对象)传递给厨师。
- 解耦 请求发送者和接收者:服务员与厨师之间不直接依赖。
- 支持扩展性:新增菜品或修改流程时无需修改服务员逻辑。
- 支持请求队列/撤销:可实现订单排队或取消功能。
- 核心类结构图
classDiagram
class Command {
<<interface>>
+execute()
}
class FoodOrderCommand {
-chef: Chef
+execute()
}
class Chef {
+cook(foodName: String)
}
class Waiter {
-command: Command
+takeOrder(command: Command)
+submitOrder()
}
class Client {
+main()
}
Command <|-- FoodOrderCommand
FoodOrderCommand --> Chef
Waiter --> Command
Client --> Waiter
Client --> Chef
- 代码实现
这里的命令,可以认为是一个传递的过程,这个过程经过三个部分,发起者,中间者和执行者。发起者通过命令,交给中间者,中间者无需关心这个命令是什么,只是去调用执行者。这个和中介模式很像。
// 使用
public class RestaurantDemo {
public static void main(String[] args) {
Chef chef = new Chef();
Command pastaOrder = new FoodOrderCommand(chef, "意大利面");
Command steakOrder = new FoodOrderCommand(chef, "牛排");
Waiter waiter = new Waiter();
waiter.takeOrder(pastaOrder);
waiter.submitOrder(); // 输出:厨师开始制作:意大利面
waiter.takeOrder(steakOrder);
waiter.submitOrder(); // 输出:厨师开始制作:牛排
}
}
// 1. 命令接口
interface Command {
void execute();
}
// 2. 具体命令(封装菜品订单)
class FoodOrderCommand implements Command {
private Chef chef;
private String foodName;
public FoodOrderCommand(Chef chef, String foodName) {
this.chef = chef;
this.foodName = foodName;
}
@Override
public void execute() {
chef.cook(foodName);
}
}
// 3. 接收者(实际执行操作的对象)
class Chef {
public void cook(String foodName) {
System.out.println("厨师开始制作:" + foodName);
}
}
// 4. 调用者(触发命令的对象)
class Waiter {
private Command command;
public void takeOrder(Command command) {
this.command = command;
}
public void submitOrder() {
if (command != null) {
command.execute();
}
}
}
- 实现效果
- 解耦:服务员只需处理命令对象,无需了解厨师具体实现。
- 可扩展性:新增菜品只需添加新的
Command子类。 - 支持复杂操作:可扩展为支持订单队列(将多个命令存储后批量执行)或撤销(在命令对象中添加
undo()方法)。 - 缺点:可能导致类的数量增加(每个具体命令都需要一个类)。
-
状态模式:
马路的交通灯是按“绿-黄-红-绿”循环变化,请设计一个交通灯 信号控制系统 。
- 名称与定义
状态模式 (State Pattern) 允许对象在其内部状态改变时改变它的行为,使对象看起来像是修改了其类。状态模式通过将每个状态的行为封装到对应的类中,消除传统条件逻辑的复杂性。
- 应用场景
- 交通灯控制:交通灯存在多个状态(绿、黄、红),不同状态的行为(切换到下一个颜色)不同。
- 状态动态切换:状态变化遵循特定顺序,且需要在运行时动态切换(如本例的“绿→黄→红→绿”循环)。
- 消除条件分支:避免在控制类中通过
if-else或switch管理状态逻辑。
- 核心类结构
classDiagram
class TrafficLight {
-currentState: TrafficLightState
+changeSignal()
+setState(TrafficLightState)
}
class TrafficLightState {
<<interface>>
+handleChange(TrafficLight)
}
class GreenLight {
+handleChange(TrafficLight)
}
class YellowLight {
+handleChange(TrafficLight)
}
class RedLight {
+handleChange(TrafficLight)
}
TrafficLight --> TrafficLightState : 当前状态
TrafficLightState <|-- GreenLight
TrafficLightState <|-- YellowLight
TrafficLightState <|-- RedLight
- Java 代码实现
对于调用方而言,我们只需要对状态模式构造的类调用他的更改状态方法, 就能够更改他的表现,就如同类被更改。其方法的变更内聚在状态类内部。
核心的类是控制状态变更(trafficLight) 的类,具体的状态变更封装在具体的状态类中。
// 期望结果
public class Client {
public static void main(String[] args) {
TrafficLight trafficLight = new TrafficLight();
// 触发状态变化
trafficLight.changeSignal(); // 绿灯→黄灯
trafficLight.changeSignal(); // 黄灯→红灯
trafficLight.changeSignal(); // 红灯→绿灯
}
}
状态接口 TrafficLightState
public interface TrafficLightState {
void handleChange(TrafficLight context);
}
具体状态类
// 绿灯状态
public class GreenLight implements TrafficLightState {
@Override
public void handleChange(TrafficLight context) {
System.out.println("绿灯 → 黄灯");
context.setState(new YellowLight());
}
}
// 黄灯状态
public class YellowLight implements TrafficLightState {
@Override
public void handleChange(TrafficLight context) {
System.out.println("黄灯 → 红灯");
context.setState(new RedLight());
}
}
// 红灯状态
public class RedLight implements TrafficLightState {
@Override
public void handleChange(TrafficLight context) {
System.out.println("红灯 → 绿灯");
context.setState(new GreenLight());
}
}
交通灯上下文 TrafficLight
public class TrafficLight {
private TrafficLightState currentState;
public TrafficLight() {
// 初始状态为绿灯
currentState = new GreenLight();
}
public void setState(TrafficLightState state) {
this.currentState = state;
}
public void changeSignal() {
currentState.handleChange(this);
}
}
- 实现效果
运行输出:
绿灯 → 黄灯
黄灯 → 红灯
红灯 → 绿灯
优势:
- 开闭原则:新增状态(如紧急状态)无需修改原有代码,只需添加新类。
- 逻辑 解耦:状态切换逻辑封装在各自类中,代码可读性高。
- 动态切换:通过
TrafficLight::setState方法可随时调整当前状态。
-
职责链模式:
某单位采购物品,如金额小于或等于5000,由主管审批;如金额小于等于10000,由部门经理审批;如金额小于等于30000,由副总审批;如果金额超过30000以上,由总经理审批。请设计如上业务流程。
- 名称与定义
职责链模式( Chain of Responsibility Pattern) : 允许将请求沿着处理链传递,每个处理者都可决定处理请求或将其传递给链中的下一个处理者。
- 应用场景
- 采购审批流程:不同金额的采购需要不同级别的审批人处理
- 请求 动态路由:需要避免请求发送者与接收者之间的紧耦合
- 多级处理逻辑:存在多个对象可以处理同一请求,但处理级别不同
- 核心类结构
职责链,顾名思义是一条链,所以有开头,从职责最小的开始进入,直到满足职责条件或者没法继续推卸责任。类比链表的样子。
classDiagram
class PurchaseRequest {
-double amount
+PurchaseRequest(double amount)
+getAmount() double
}
class Approver {
<<abstract>>
#String name
#Approver nextApprover
+setNextApprover(Approver nextApprover)
+processRequest(PurchaseRequest request)* void
}
class Director {
+processRequest(PurchaseRequest request)
}
class Manager {
+processRequest(PurchaseRequest request)
}
class VicePresident {
+processRequest(PurchaseRequest request)
}
class President {
+processRequest(PurchaseRequest request)
}
Approver <|-- Director
Approver <|-- Manager
Approver <|-- VicePresident
Approver <|-- President
Approver o-- Approver : nextApprover
PurchaseRequest <-- Approver : processes
- 代码实现(Java)
// 测试类
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// 构建职责链
Approver director = new Director("张主管");
Approver manager = new Manager("李经理");
Approver vp = new VicePresident("王副总");
Approver president = new President("赵总");
director.setNextApprover(manager);
manager.setNextApprover(vp);
vp.setNextApprover(president);
// 创建不同金额的请求
director.processRequest(new PurchaseRequest(4000));
director.processRequest(new PurchaseRequest(8000));
director.processRequest(new PurchaseRequest(25000));
director.processRequest(new PurchaseRequest(50000));
}
}
// 请求对象
public class PurchaseRequest {
private double amount;
public PurchaseRequest(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
// 抽象处理者
abstract class Approver {
protected String name;
protected Approver nextApprover;
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
public abstract void processRequest(PurchaseRequest request);
}
// 具体处理者:主管
class Director extends Approver {
public Director(String name) {
this.name = name;
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 5000) {
System.out.println("主管 [" + name + "] 审批了采购申请,金额:" + request.getAmount());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 具体处理者:部门经理
class Manager extends Approver {
public Manager(String name) {
this.name = name;
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 10000) {
System.out.println("经理 [" + name + "] 审批了采购申请,金额:" + request.getAmount());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 具体处理者:副总
class VicePresident extends Approver {
public VicePresident(String name) {
this.name = name;
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 30000) {
System.out.println("副总 [" + name + "] 审批了采购申请,金额:" + request.getAmount());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 具体处理者:总经理
class President extends Approver {
public President(String name) {
this.name = name;
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() > 30000) {
System.out.println("总经理 [" + name + "] 审批了采购申请,金额:" + request.getAmount());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
- 实现效果
主管 [张主管] 审批了采购申请,金额:4000.0
经理 [李经理] 审批了采购申请,金额:8000.0
副总 [王副总] 审批了采购申请,金额:25000.0
总经理 [赵总] 审批了采购申请,金额:50000.0
模式优势:
- 解耦 请求发送者和接收者:客户端只需将请求发送到链头
- 动态调整处理流程:可通过修改链结构灵活调整审批规则
- 符合 开闭原则:新增处理者时无需修改现有代码
-
中介者模式:
现代智能家居,根据用户需求制定智能家居相互间的联动效果:如闹钟响起后,咖啡机会煮咖啡,并打开TV,观看热点新闻,咖啡煮好后,拉起窗帘并关闭TV,请设计该控制系统。
- 名称 & 定义
中介者模式 ( Mediator Pattern) :通过定义一个中介对象来封装一系列对象之间的交互关系,使各对象不再显式地互相引用,解耦对象间的直接通信,使系统可独立地改变对象间的交互逻辑。
- 应用场景
- 智能家居设备联动:当多个智能设备(如闹钟、咖啡机、TV)需要通过复杂规则联动时
- 系统 解耦 需求:当设备间直接通信会形成网状依赖关系时(如一个设备触发多个设备的操作)
- 核心类结构图
classDiagram
class Mediator {
<<interface>>
+handleEvent(source: Colleague, eventType: String)
}
class SmartHomeMediator {
-alarm: Alarm
-coffeeMaker: CoffeeMaker
-tv: TV
-curtain: Curtain
+handleEvent(source, eventType)
}
class Colleague {
-mediator: Mediator
+triggerEvent(eventType: String)
+setMediator(mediator: Mediator)
}
class Alarm
class CoffeeMaker
class TV
class Curtain
Mediator <|.. SmartHomeMediator
Colleague <|-- Alarm
Colleague <|-- CoffeeMaker
Colleague <|-- TV
Colleague <|-- Curtain
SmartHomeMediator --> Alarm
SmartHomeMediator --> CoffeeMaker
SmartHomeMediator --> TV
SmartHomeMediator --> Curtain
- 代码实现
// 客户端调用
public class Client {
public static void main(String[] args) {
SmartHomeMediator mediator = new SmartHomeMediator();
Alarm alarm = new Alarm();
CoffeeMaker coffeeMaker = new CoffeeMaker();
TV tv = new TV();
Curtain curtain = new Curtain();
// 设置中介者
mediator.setAlarm(alarm);
mediator.setCoffeeMaker(coffeeMaker);
mediator.setTV(tv);
mediator.setCurtain(curtain);
// 给设备设置中介者引用
alarm.setMediator(mediator);
coffeeMaker.setMediator(mediator);
tv.setMediator(mediator);
curtain.setMediator(mediator);
// 触发事件
System.out.println("==== 早晨起床场景 ====");
alarm.ring();
// 模拟咖啡煮好后(实际可能需要事件监听)
try { Thread.sleep(2500); } catch (InterruptedException e) {}
coffeeMaker.triggerEvent("coffeeDone");
}
}
中介者接口
public interface Mediator {
void handleEvent(Colleague colleague, String eventType);
}
具体中介者
就如同一个递归,智能家居控制器和家具之间保持双向引用,家具执行后调用智能家居,由智能家具调度后面的家居执行,如此往复。
public class SmartHomeMediator implements Mediator {
private Alarm alarm;
private CoffeeMaker coffeeMaker;
private TV tv;
private Curtain curtain;
// 构造函数中设置关联对象
public void setAlarm(Alarm alarm) { this.alarm = alarm; }
public void setCoffeeMaker(CoffeeMaker coffeeMaker) { this.coffeeMaker = coffeeMaker; }
public void setTV(TV tv) { this.tv = tv; }
public void setCurtain(Curtain curtain) { this.curtain = curtain; }
@Override
public void handleEvent(Colleague colleague, String eventType) {
if (colleague instanceof Alarm && "alarmRang".equals(eventType)) {
coffeeMaker.brewCoffee();
tv.turnOn();
} else if (colleague instanceof CoffeeMaker && "coffeeDone".equals(eventType)) {
curtain.open();
tv.turnOff();
}
}
}
同事类基类
public abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public void triggerEvent(String eventType) {
mediator.handleEvent(this, eventType);
}
}
具体设备类
public class Alarm extends Colleague {
public void ring() {
System.out.println(">>> 闹钟响了!");
super.triggerEvent("alarmRang");
}
}
public class CoffeeMaker extends Colleague {
public void brewCoffee() {
System.out.println("☕ 咖啡机开始煮咖啡...");
// 模拟煮咖啡过程(实际可能是异步操作)
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("✅ 咖啡煮好了!");
super.triggerEvent("coffeeDone");
}
}
public class TV extends Colleague {
public void turnOn() { System.out.println("📺 电视开启,播放新闻频道..."); }
public void turnOff() { System.out.println("📺 电视关闭"); }
}
public class Curtain extends Colleague {
public void open() { System.out.println("🪟 窗帘自动打开"); }
}
- 实现效果
运行输出:
==== 早晨起床场景 ====
>>> 闹钟响了!
☕ 咖啡机开始煮咖啡...
📺 电视开启,播放新闻频道...
✅ 咖啡煮好了!
🪟 窗帘自动打开
📺 电视关闭
设计优势:
- 解耦 设备关系:设备间不直接耦合,通过中介者集中处理协作逻辑
- 扩展性增强:新增联动规则不会影响到现有设备类
- 逻辑集中管理:所有设备协作逻辑统一维护在
SmartHomeMediator中
注意事项:
- 中介者类可能变得庞大复杂(可采用分布式中介者解决)
- 同步/异步调用需要特殊处理(如异步任务完成后回调中介者)
-
解释器模式(Interpreter Pattern)
定义
将语言中的句子表示为抽象语法树,并定义一个解释器来解释这些句子。
应用场景
- 需要解析特定语法规则的场景(如数学表达式、SQL解析)
- 编译器设计或规则引擎开发
核心类结构
classDiagram
class Expression {
+interpret(Context): void
}
class TerminalExpression {
+interpret(Context): void
}
class NonTerminalExpression {
-expression1: Expression
-expression2: Expression
+interpret(Context): void
}
class Context {
-variables: Map<String, Boolean>
+lookup(String): Boolean
}
Expression <|-- TerminalExpression
Expression <|-- NonTerminalExpression
Context --> Expression
代码实现
// 抽象表达式接口
interface Expression {
boolean interpret(Context context);
}
// 终结符表达式
class TerminalExpression implements Expression {
private String variable;
public TerminalExpression(String variable) {
this.variable = variable; }
public boolean interpret(Context context) {
return context.lookup(variable);
}
}
// 非终结符表达式(AND逻辑)
class AndExpression implements Expression {
private Expression expr1;
private Expression expr2;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(Context context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
// 上下文类
class Context {
private Map<String, Boolean> variables = new HashMap<>();
public void assign(String var, boolean value) {
variables.put(var, value);
}
public boolean lookup(String var) {
return variables.getOrDefault(var, false);
}
}
// 使用示例
Context context = new Context();
context.assign("A", true);
context.assign("B", false);
Expression expr = new AndExpression(
new TerminalExpression("A"),
new TerminalExpression("B")
);
System.out.println(expr.interpret(context)); // 输出 false
实现流程
- 定义抽象表达式接口
Expression - 实现终结符表达式(如
TerminalExpression)和非终结符表达式(如AndExpression) - 在上下文
Context中维护变量状态 - 通过组合表达式对象构建语法树并解释执行
适用场景:开发一个规则引擎,用于解析用户自定义的布尔逻辑规则(如(A && B) || C)并动态计算结果。
-
访问者模式(Visitor Pattern)
定义
将算法与对象结构分离,允许在不修改元素类的前提下定义新操作。
应用场景
- 对象结构稳定但需要频繁新增操作(如文档导出、统计计算)
- 跨多个异构类的统一操作(如XML节点处理)
核心类结构
classDiagram
class Element {
+accept(Visitor): void
}
class ConcreteElementA {
+accept(Visitor): void
+operationA(): void
}
class ConcreteElementB {
+accept(Visitor): void
+operationB(): void
}
class Visitor {
+visit(ConcreteElementA): void
+visit(ConcreteElementB): void
}
class ConcreteVisitor {
+visit(ConcreteElementA): void
+visit(ConcreteElementB): void
}
Element <|-- ConcreteElementA
Element <|-- ConcreteElementB
Visitor <|-- ConcreteVisitor
ConcreteElementA --> Visitor
ConcreteElementB --> Visitor
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素类
class ConcreteElementA implements Element {
public void accept(Visitor visitor) { visitor.visit(this); }
public String operationA() { return "ElementA"; }
}
class ConcreteElementB implements Element {
public void accept(Visitor visitor) { visitor.visit(this); }
public String operationB() { return "ElementB"; }
}
// 访问者接口
interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
// 具体访问者(实现导出功能)
class ConcreteVisitor implements Visitor {
public void visit(ConcreteElementA element) {
System.out.println("Exporting: " + element.operationA());
}
public void visit(ConcreteElementB element) {
System.out.println("Exporting: " + element.operationB());
}
}
// 使用示例
List<Element> elements = Arrays.asList(
new ConcreteElementA(),
new ConcreteElementB()
);
Visitor exporter = new ConcreteVisitor();
elements.forEach(e -> e.accept(exporter));
// 输出:
// Exporting: ElementA
// Exporting: ElementB
实现流程
- 定义
Element接口和具体元素类 - 创建
Visitor接口及其实现类(如ConcreteVisitor) - 元素通过
accept()方法调用访问者的visit()方法 - 访问者针对不同元素类型实现不同处理逻辑
适用场景:开发一个文档处理系统,需要支持多种格式导出(如PDF、XML),但文档结构(段落、图片)固定不变。
-
迭代器模式(Iterator Pattern)
定义
提供一种方法顺序访问聚合对象中的元素,而无需暴露其内部表示。
应用场景
- 需要统一遍历不同数据结构(如数组、树、图)
- 隐藏集合内部实现,提供多种遍历方式(如正序、逆序)
核心类结构
classDiagram
class Aggregate {
+createIterator(): Iterator
}
class ConcreteAggregate {
-items: List<Object>
+createIterator(): Iterator
}
class Iterator {
+hasNext(): boolean
+next(): Object
}
class ConcreteIterator {
-index: int
+hasNext(): boolean
+next(): Object
}
Aggregate <|-- ConcreteAggregate
Iterator <|-- ConcreteIterator
ConcreteAggregate --> ConcreteIterator
// 迭代器接口
interface Iterator<T> {
boolean hasNext();
T next();
}
// 聚合接口
interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体聚合类
class ConcreteAggregate implements Aggregate<String> {
private List<String> items = new ArrayList<>();
public void addItem(String item) { items.add(item); }
public Iterator<String> createIterator() {
return new ConcreteIterator(items);
}
}
// 具体迭代器
class ConcreteIterator implements Iterator<String> {
private List<String> items;
private int index = 0;
public ConcreteIterator(List<String> items) { this.items = items; }
public boolean hasNext() { return index < items.size(); }
public String next() { return items.get(index++); }
}
// 使用示例
ConcreteAggregate aggregate = new ConcreteAggregate();
aggregate.addItem("Item1");
aggregate.addItem("Item2");
Iterator<String> iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 输出:
// Item1
// Item2
实现流程
- 定义
Iterator接口和Aggregate接口 - 实现具体聚合类(如
ConcreteAggregate)和迭代器类(如ConcreteIterator) - 通过
createIterator()方法返回迭代器实例 - 客户端通过迭代器统一遍历聚合对象
适用场景:开发一个支持多种数据源(数据库、文件系统)的日志分析工具,需要统一遍历日志条目而不暴露底层存储细节
-
中介者模式(Mediator Pattern)
定义
用一个中介对象封装一系列对象交互,降低对象间耦合度
应用场景
- 对象间存在复杂网状依赖(如GUI组件通信)
- 需要集中控制多个对象的交互逻辑(如聊天室消息路由)
核心类结构
classDiagram
class Mediator {
+notify(Colleague): void
}
class ConcreteMediator {
-colleague1: Colleague
-colleague2: Colleague
+notify(Colleague): void
}
class Colleague {
-mediator: Mediator
+send(): void
+receive(): void
}
class ConcreteColleague1 {
+send(): void
+receive(): void
}
class ConcreteColleague2 {
+send(): void
+receive(): void
}
Mediator <|-- ConcreteMediator
Colleague <|-- ConcreteColleague1
Colleague <|-- ConcreteColleague2
ConcreteMediator --> Colleague
Colleague --> Mediator
代码实现
// 中介者接口
interface Mediator {
void notify(Colleague sender, String message);
}
// 具体中介者(聊天室)
class ChatRoom implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();
public void addColleague(Colleague colleague) {
colleagues.add(colleague);
}
public void notify(Colleague sender, String message) {
for (Colleague c : colleagues) {
if (c != sender) c.receive(message);
}
}
}
// 同事类接口
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) { this.mediator = mediator; }
public abstract void send(String message);
public abstract void receive(String message);
}
// 具体同事类(用户)
class User extends Colleague {
private String name;
public User(Mediator mediator, String name) {
super(mediator);
this.name = name;
}
public void send(String message) {
System.out.println(name + " 发送: " + message);
mediator.notify(this, message);
}
public void receive(String message) {
System.out.println(name + " 收到: " + message);
}
}
// 使用示例
ChatRoom chatRoom = new ChatRoom();
User alice = new User(chatRoom, "Alice");
User bob = new User(chatRoom, "Bob");
chatRoom.addColleague(alice);
chatRoom.addColleague(bob);
alice.send("你好,Bob!");
// 输出:
// Alice 发送: 你好,Bob!
// Bob 收到: 你好,Bob!
实现流程
- 定义
Mediator接口和具体中介者(如ChatRoom) - 实现
Colleague抽象类及其子类(如User) - 同事对象通过中介者转发消息
- 中介者集中管理消息路由逻辑
适用场景:开发一个多用户聊天系统,需要避免用户之间直接引用,通过聊天室服务器统一转发消息。