跳到主要内容

Java 设计模式面试题集

总题数: 36道 | 重点领域: 设计原则、创建型、结构型、行为型 | 难度分布: 中高级

本文档整理了 Java 设计模式的完整36道面试题目,涵盖设计原则、各种设计模式的应用场景和实现原理。


面试题目列表

1. 什么是设计模式?请简述其作用。

答案:

设计模式是软件开发中经过验证的、可复用的解决方案。

定义:

  • 是在特定场景下对常见问题的通用解决方案
  • 不是代码,而是解决问题的思路和方法
  • 是前人经验的总结和提炼

主要作用:

  1. 提高代码复用性:减少重复代码
  2. 增强可维护性:代码结构清晰,易于理解
  3. 提升系统扩展性:方便添加新功能
  4. 降低耦合度:模块间依赖减少
  5. 统一开发语言:团队沟通更高效

2. 23 种设计模式分为哪三大类?

答案:

一、创建型模式(5种) 关注对象的创建过程

  1. 单例模式(Singleton)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)
  4. 建造者模式(Builder)
  5. 原型模式(Prototype)

二、结构型模式(7种) 关注类和对象的组合

  1. 适配器模式(Adapter)
  2. 桥接模式(Bridge)
  3. 组合模式(Composite)
  4. 装饰器模式(Decorator)
  5. 外观模式(Facade)
  6. 享元模式(Flyweight)
  7. 代理模式(Proxy)

三、行为型模式(11种) 关注对象间的通信和职责分配

  1. 观察者模式(Observer)
  2. 迭代器模式(Iterator)
  3. 模板方法模式(Template Method)
  4. 命令模式(Command)
  5. 状态模式(State)
  6. 策略模式(Strategy)
  7. 责任链模式(Chain of Responsibility)
  8. 中介者模式(Mediator)
  9. 访问者模式(Visitor)
  10. 备忘录模式(Memento)
  11. 解释器模式(Interpreter)

3. 请解释什么是单例模式,并给出一个使用场景

答案:

单例模式确保一个类只有一个实例,并提供全局访问点。

核心要素:

  1. 私有构造函数(防止外部实例化)
  2. 静态实例变量
  3. 公共静态获取方法

基本实现:

java
1// 饥饿式(线程安全)
2public class Singleton {
3 // 静态实例
4 private static final Singleton instance = new Singleton();
5
6 // 私有构造
7 private Singleton() {}
8
9 // 公共获取方法
10 public static Singleton getInstance() {
11 return instance;
12 }
13}

常见使用场景:

  1. 数据库连接池
java
1public class ConnectionPool {
2 private static ConnectionPool instance;
3 private List<Connection> connections;
4
5 private ConnectionPool() {
6 connections = new ArrayList<>();
7 // 初始化连接池
8 }
9
10 public static ConnectionPool getInstance() {
11 if (instance == null) {
12 instance = new ConnectionPool();
13 }
14 return instance;
15 }
16}
  1. 配置管理器
java
1public class ConfigManager {
2 private static ConfigManager instance;
3 private Properties config;
4
5 private ConfigManager() {
6 config = new Properties();
7 // 加载配置文件
8 }
9
10 public static ConfigManager getInstance() {
11 if (instance == null) {
12 instance = new ConfigManager();
13 }
14 return instance;
15 }
16}
  1. 日志工具
java
1public class Logger {
2 private static Logger instance;
3
4 private Logger() {}
5
6 public static Logger getInstance() {
7 if (instance == null) {
8 instance = new Logger();
9 }
10 return instance;
11 }
12
13 public void log(String message) {
14 System.out.println(message);
15 }
16}

4. 单例模式有哪几种实现?如何保证线程安全?

答案:

1. 饥饿式(线程安全)

java
1public class Singleton {
2 // 类加载时创建实例
3 private static final Singleton instance = new Singleton();
4
5 private Singleton() {}
6
7 public static Singleton getInstance() {
8 return instance;
9 }
10}
11
12// 优点:简单,线程安全
13// 缺点:不能延迟加载

2. 懒汉式(非线程安全)

java
1public class Singleton {
2 private static Singleton instance;
3
4 private Singleton() {}
5
6 public static Singleton getInstance() {
7 if (instance == null) {
8 instance = new Singleton();
9 }
10 return instance;
11 }
12}
13
14// 优点:延迟加载
15// 缺点:非线程安全

3. 同步方法(线程安全,性能低)

java
1public class Singleton {
2 private static Singleton instance;
3
4 private Singleton() {}
5
6 public static synchronized Singleton getInstance() {
7 if (instance == null) {
8 instance = new Singleton();
9 }
10 return instance;
11 }
12}
13
14// 优点:线程安全
15// 缺点:每次调用都同步,性能低

4. 双重检查锁(DCL,推荐)

java
1public class Singleton {
2 // volatile保证可见性
3 private static volatile Singleton instance;
4
5 private Singleton() {}
6
7 public static Singleton getInstance() {
8 if (instance == null) { // 第一次检查
9 synchronized (Singleton.class) {
10 if (instance == null) { // 第二次检查
11 instance = new Singleton();
12 }
13 }
14 }
15 return instance;
16 }
17}
18
19// 优点:线程安全,延迟加载,性能好
20// 注意:必须使用volatile

5. 静态内部类(推荐)

java
1public class Singleton {
2 private Singleton() {}
3
4 // 静态内部类
5 private static class SingletonHolder {
6 private static final Singleton INSTANCE = new Singleton();
7 }
8
9 public static Singleton getInstance() {
10 return SingletonHolder.INSTANCE;
11 }
12}
13
14// 优点:线程安全,延迟加载,简洁
15// 原理:类加载机制保证线程安全

6. 枚举单例(最佳实践)

java
1public enum Singleton {
2 INSTANCE;
3
4 public void doSomething() {
5 System.out.println("Singleton");
6 }
7}
8
9// 使用
10Singleton.INSTANCE.doSomething();
11
12// 优点:
13// 1. 线程安全
14// 2. 防止反射攻击
15// 3. 防止反序列化创建新对象
16// 4. 代码简洁

线程安全对比:

实现方式线程安全延迟加载性能推荐度
饥饿式×★★★
懒汉式××
同步方法
双重检查★★★★
静态内部类★★★★★
枚举×★★★★★

5. 工厂模式和抽象工厂模式有什么区别?

答案:

工厂方法模式: 创建一种产品,不同工厂生产不同的实现。

java
1// 产品接口
2interface Product {
3 void use();
4}
5
6// 具体产品A
7class ProductA implements Product {
8 public void use() {
9 System.out.println("Using Product A");
10 }
11}
12
13// 具体产品B
14class ProductB implements Product {
15 public void use() {
16 System.out.println("Using Product B");
17 }
18}
19
20// 抽象工厂
21abstract class Factory {
22 abstract Product createProduct();
23}
24
25// 具体工厂A
26class FactoryA extends Factory {
27 Product createProduct() {
28 return new ProductA();
29 }
30}
31
32// 具体工厂B
33class FactoryB extends Factory {
34 Product createProduct() {
35 return new ProductB();
36 }
37}

抽象工厂模式: 创建一系列相关产品,一个工厂生产多种产品。

java
1// 产品族系1:按钮
2interface Button {
3 void click();
4}
5
6class WindowsButton implements Button {
7 public void click() {
8 System.out.println("Windows Button");
9 }
10}
11
12class MacButton implements Button {
13 public void click() {
14 System.out.println("Mac Button");
15 }
16}
17
18// 产品族系2:文本框
19interface TextBox {
20 void input();
21}
22
23class WindowsTextBox implements TextBox {
24 public void input() {
25 System.out.println("Windows TextBox");
26 }
27}
28
29class MacTextBox implements TextBox {
30 public void input() {
31 System.out.println("Mac TextBox");
32 }
33}
34
35// 抽象工厂
36interface GUIFactory {
37 Button createButton();
38 TextBox createTextBox();
39}
40
41// Windows工厂
42class WindowsFactory implements GUIFactory {
43 public Button createButton() {
44 return new WindowsButton();
45 }
46 public TextBox createTextBox() {
47 return new WindowsTextBox();
48 }
49}
50
51// Mac工厂
52class MacFactory implements GUIFactory {
53 public Button createButton() {
54 return new MacButton();
55 }
56 public TextBox createTextBox() {
57 return new MacTextBox();
58 }
59}

主要区别:

特性工厂方法模式抽象工厂模式
产品数量一种产品多种相关产品
工厂层次一层两层(抽象+具体)
复杂度简单复杂
使用场景单一产品的创建产品族的创建
示例创建不同数据库连接创建不同UI风格组件

6. 请描述简单工厂模式的工作原理。

答案:

简单工厂模式通过一个工厂类根据参数创建不同的产品实例。

基本实现:

java
1// 产品接口
2interface Shape {
3 void draw();
4}
5
6// 具体产品
7class Circle implements Shape {
8 public void draw() {
9 System.out.println("Drawing Circle");
10 }
11}
12
13class Rectangle implements Shape {
14 public void draw() {
15 System.out.println("Drawing Rectangle");
16 }
17}
18
19class Triangle implements Shape {
20 public void draw() {
21 System.out.println("Drawing Triangle");
22 }
23}
24
25// 简单工厂
26class ShapeFactory {
27 // 根据类型创建对象
28 public static Shape createShape(String type) {
29 if (type == null) {
30 return null;
31 }
32 if (type.equalsIgnoreCase("CIRCLE")) {
33 return new Circle();
34 } else if (type.equalsIgnoreCase("RECTANGLE")) {
35 return new Rectangle();
36 } else if (type.equalsIgnoreCase("TRIANGLE")) {
37 return new Triangle();
38 }
39 return null;
40 }
41}
42
43// 使用
44public class Demo {
45 public static void main(String[] args) {
46 Shape circle = ShapeFactory.createShape("CIRCLE");
47 circle.draw();
48
49 Shape rectangle = ShapeFactory.createShape("RECTANGLE");
50 rectangle.draw();
51 }
52}

优缺点:

优点:

  • 封装对象创建逻辑
  • 客户端不需知道具体类名
  • 代码简单,易于理解

缺点:

  • 违反开闭原则(添加新产品需修改工厂类)
  • 工厂类职责过重

7. 什么是建造者模式?一般用在什么场景?

答案:

建造者模式将复杂对象的构建过程与表示分离,逐步构建对象。

实现示例:

java
1// 产品类
2class Computer {
3 private String cpu;
4 private String ram;
5 private String storage;
6 private String gpu;
7
8 // 私有构造函数
9 private Computer(Builder builder) {
10 this.cpu = builder.cpu;
11 this.ram = builder.ram;
12 this.storage = builder.storage;
13 this.gpu = builder.gpu;
14 }
15
16 // 静态内部建造者类
17 public static class Builder {
18 private String cpu;
19 private String ram;
20 private String storage;
21 private String gpu;
22
23 public Builder cpu(String cpu) {
24 this.cpu = cpu;
25 return this;
26 }
27
28 public Builder ram(String ram) {
29 this.ram = ram;
30 return this;
31 }
32
33 public Builder storage(String storage) {
34 this.storage = storage;
35 return this;
36 }
37
38 public Builder gpu(String gpu) {
39 this.gpu = gpu;
40 return this;
41 }
42
43 public Computer build() {
44 return new Computer(this);
45 }
46 }
47
48 @Override
49 public String toString() {
50 return "Computer{cpu='" + cpu + "', ram='" + ram +
51 "', storage='" + storage + "', gpu='" + gpu + "'}";
52 }
53}
54
55// 使用
56public class Demo {
57 public static void main(String[] args) {
58 Computer computer = new Computer.Builder()
59 .cpu("Intel i7")
60 .ram("16GB")
61 .storage("512GB SSD")
62 .gpu("NVIDIA RTX 3060")
63 .build();
64
65 System.out.println(computer);
66 }
67}

使用场景:

  1. 对象有很多参数:避免构造函数参数过多
  2. 参数有可选项:灵活配置对象
  3. 需要不可变对象:Builder构建后对象不可变

实际应用:

  • StringBuilder/StringBuffer
  • Lombok的@Builder注解
  • OkHttp的Request.Builder
  • Retrofit的配置

8. 什么是原型模式?一般用在什么场景?

答案:

原型模式通过复制现有对象来创建新对象,而不是通过new。

实现方式:

1. 浅克隆:

java
1class Sheep implements Cloneable {
2 private String name;
3 private int age;
4
5 public Sheep(String name, int age) {
6 this.name = name;
7 this.age = age;
8 }
9
10 @Override
11 protected Object clone() throws CloneNotSupportedException {
12 return super.clone();
13 }
14}
15
16// 使用
17Sheep original = new Sheep("Dolly", 3);
18Sheep cloned = (Sheep) original.clone();

2. 深克隆:

java
1class Address implements Cloneable {
2 private String city;
3
4 public Address(String city) {
5 this.city = city;
6 }
7
8 @Override
9 protected Object clone() throws CloneNotSupportedException {
10 return super.clone();
11 }
12}
13
14class Person implements Cloneable {
15 private String name;
16 private Address address;
17
18 public Person(String name, Address address) {
19 this.name = name;
20 this.address = address;
21 }
22
23 @Override
24 protected Object clone() throws CloneNotSupportedException {
25 Person cloned = (Person) super.clone();
26 // 深克隆:复制引用对象
27 cloned.address = (Address) address.clone();
28 return cloned;
29 }
30}

使用场景:

  1. 对象创建成本高:复制比新建快
  2. 需要保存对象状态:备份、撤销功能
  3. 避免复杂的初始化:直接复制已初始化对象

实际应用:

java
1// Spring中Bean的prototype作用域
2@Scope("prototype")
3public class MyBean {
4 // ...
5}
6
7// Java集合的clone
8ArrayList<String> list1 = new ArrayList<>();
9ArrayList<String> list2 = (ArrayList<String>) list1.clone();

9. 什么是适配器模式?一般用在什么场景?

答案:

适配器模式将一个类的接口转换成客户端期望的另一个接口。

类适配器(继承):

java
1// 目标接口
2interface MediaPlayer {
3 void play(String audioType, String fileName);
4}
5
6// 被适配的类
7class VlcPlayer {
8 public void playVlc(String fileName) {
9 System.out.println("Playing vlc file: " + fileName);
10 }
11}
12
13class Mp4Player {
14 public void playMp4(String fileName) {
15 System.out.println("Playing mp4 file: " + fileName);
16 }
17}
18
19// 适配器
20class MediaAdapter implements MediaPlayer {
21 private VlcPlayer vlcPlayer;
22 private Mp4Player mp4Player;
23
24 public MediaAdapter(String audioType) {
25 if (audioType.equalsIgnoreCase("vlc")) {
26 vlcPlayer = new VlcPlayer();
27 } else if (audioType.equalsIgnoreCase("mp4")) {
28 mp4Player = new Mp4Player();
29 }
30 }
31
32 @Override
33 public void play(String audioType, String fileName) {
34 if (audioType.equalsIgnoreCase("vlc")) {
35 vlcPlayer.playVlc(fileName);
36 } else if (audioType.equalsIgnoreCase("mp4")) {
37 mp4Player.playMp4(fileName);
38 }
39 }
40}
41
42// 使用
43class AudioPlayer implements MediaPlayer {
44 private MediaAdapter mediaAdapter;
45
46 @Override
47 public void play(String audioType, String fileName) {
48 if (audioType.equalsIgnoreCase("mp3")) {
49 System.out.println("Playing mp3 file: " + fileName);
50 } else if (audioType.equalsIgnoreCase("vlc") ||
51 audioType.equalsIgnoreCase("mp4")) {
52 mediaAdapter = new MediaAdapter(audioType);
53 mediaAdapter.play(audioType, fileName);
54 } else {
55 System.out.println("Invalid media type");
56 }
57 }
58}

使用场景:

  1. 系统集成:旧系统与新系统接口不兼容
  2. 第三方库适配:封装第三方接口
  3. 接口转换:不同接口间的转换

实际应用:

java
1// Java IO中的适配器
2InputStreamReader isr = new InputStreamReader(new FileInputStream("file.txt"));
3
4// Arrays.asList()
5List<String> list = Arrays.asList("a", "b", "c");
6
7// Spring MVC中的HandlerAdapter

10. 什么是桥接模式?一般用在什么场景?

答案:

桥接模式将抽象部分与实现部分分离,使它们可以独立变化。

实现示例:

java
1// 实现部分:颜色
2interface Color {
3 void applyColor();
4}
5
6class RedColor implements Color {
7 public void applyColor() {
8 System.out.println("Red color");
9 }
10}
11
12class BlueColor implements Color {
13 public void applyColor() {
14 System.out.println("Blue color");
15 }
16}
17
18// 抽象部分:形状
19abstract class Shape {
20 protected Color color; // 桥接
21
22 public Shape(Color color) {
23 this.color = color;
24 }
25
26 abstract void draw();
27}
28
29class Circle extends Shape {
30 public Circle(Color color) {
31 super(color);
32 }
33
34 @Override
35 void draw() {
36 System.out.print("Circle with ");
37 color.applyColor();
38 }
39}
40
41class Rectangle extends Shape {
42 public Rectangle(Color color) {
43 super(color);
44 }
45
46 @Override
47 void draw() {
48 System.out.print("Rectangle with ");
49 color.applyColor();
50 }
51}
52
53// 使用
54public class Demo {
55 public static void main(String[] args) {
56 Shape redCircle = new Circle(new RedColor());
57 redCircle.draw();
58
59 Shape blueRectangle = new Rectangle(new BlueColor());
60 blueRectangle.draw();
61 }
62}

优势:

  • 抽象和实现分离,可独立扩展
  • 避免类爆炸(不用为每种组合创建类)
  • 符合开闭原则

使用场景:

  1. 多维度变化:形状+颜色、设备+系统
  2. 避免继承爆炸:用组合替代继承
  3. 跨平台开发:业务逻辑与平台实现分离

实际应用:

java
1// JDBC驱动
2Connection conn = DriverManager.getConnection(url);
3
4// 日志框架:SLF4J + Logback/Log4j
5Logger logger = LoggerFactory.getLogger(MyClass.class);

11. 什么是组合模式?一般用在什么场景?

答案:

组合模式将对象组合成树形结构,表示“部分-整体”层次结构。

实现示例:

java
1// 组件接口
2abstract class Component {
3 protected String name;
4
5 public Component(String name) {
6 this.name = name;
7 }
8
9 abstract void add(Component component);
10 abstract void remove(Component component);
11 abstract void display(int depth);
12}
13
14// 叶子节点:文件
15class File extends Component {
16 public File(String name) {
17 super(name);
18 }
19
20 @Override
21 void add(Component component) {
22 throw new UnsupportedOperationException();
23 }
24
25 @Override
26 void remove(Component component) {
27 throw new UnsupportedOperationException();
28 }
29
30 @Override
31 void display(int depth) {
32 System.out.println("-".repeat(depth) + name);
33 }
34}
35
36// 容器节点:文件夹
37class Folder extends Component {
38 private List<Component> children = new ArrayList<>();
39
40 public Folder(String name) {
41 super(name);
42 }
43
44 @Override
45 void add(Component component) {
46 children.add(component);
47 }
48
49 @Override
50 void remove(Component component) {
51 children.remove(component);
52 }
53
54 @Override
55 void display(int depth) {
56 System.out.println("-".repeat(depth) + name);
57 for (Component component : children) {
58 component.display(depth + 2);
59 }
60 }
61}
62
63// 使用
64public class Demo {
65 public static void main(String[] args) {
66 Folder root = new Folder("root");
67 Folder folder1 = new Folder("folder1");
68 Folder folder2 = new Folder("folder2");
69
70 File file1 = new File("file1.txt");
71 File file2 = new File("file2.txt");
72 File file3 = new File("file3.txt");
73
74 root.add(folder1);
75 root.add(folder2);
76 folder1.add(file1);
77 folder1.add(file2);
78 folder2.add(file3);
79
80 root.display(0);
81 }
82}

使用场景:

  1. 树形结构:文件系统、组织架构
  2. 部分-整体关系:菜单系统、UI组件
  3. 递归处理:需要递归遍历的场景

12. 什么是装饰器模式?一般用在什么场景?

答案:

装饰器模式动态地给对象添加额外的职责,不改变原有结构。

实现示例:

java
1// 组件接口
2interface Coffee {
3 double cost();
4 String description();
5}
6
7// 具体组件
8class SimpleCoffee implements Coffee {
9 @Override
10 public double cost() {
11 return 10.0;
12 }
13
14 @Override
15 public String description() {
16 return "Simple Coffee";
17 }
18}
19
20// 抽象装饰器
21abstract class CoffeeDecorator implements Coffee {
22 protected Coffee coffee;
23
24 public CoffeeDecorator(Coffee coffee) {
25 this.coffee = coffee;
26 }
27
28 @Override
29 public double cost() {
30 return coffee.cost();
31 }
32
33 @Override
34 public String description() {
35 return coffee.description();
36 }
37}
38
39// 具体装饰器:牛奶
40class MilkDecorator extends CoffeeDecorator {
41 public MilkDecorator(Coffee coffee) {
42 super(coffee);
43 }
44
45 @Override
46 public double cost() {
47 return super.cost() + 2.0;
48 }
49
50 @Override
51 public String description() {
52 return super.description() + ", Milk";
53 }
54}
55
56// 具体装饰器:糖
57class SugarDecorator extends CoffeeDecorator {
58 public SugarDecorator(Coffee coffee) {
59 super(coffee);
60 }
61
62 @Override
63 public double cost() {
64 return super.cost() + 1.0;
65 }
66
67 @Override
68 public String description() {
69 return super.description() + ", Sugar";
70 }
71}
72
73// 使用
74public class Demo {
75 public static void main(String[] args) {
76 Coffee coffee = new SimpleCoffee();
77 System.out.println(coffee.description() + " $" + coffee.cost());
78
79 coffee = new MilkDecorator(coffee);
80 System.out.println(coffee.description() + " $" + coffee.cost());
81
82 coffee = new SugarDecorator(coffee);
83 System.out.println(coffee.description() + " $" + coffee.cost());
84 }
85}

使用场景:

  1. 动态扩展功能:不修改原类添加功能
  2. 避免类爆炸:不用为每种组合创建子类
  3. 符合开闭原则:对扩展开放,对修改关闭

实际应用:

  • Java IO:BufferedReader/BufferedWriter
  • Collections.synchronizedList()
  • Spring的BeanWrapper

13. 装饰器、适配器、代理、桥接这四种设计模式有什么区别?

答案:

模式目的特点示例
装饰器增强功能不改变接口,动态添加职责BufferedReader
适配器接口转换让不兼容的接口协同工作InputStreamReader
代理控制访问为对象提供代理,控制访问Spring AOP
桥接分离抽象和实现抽象和实现可独立变化JDBC Driver

详细对比:

1. 装饰器模式

java
1// 目的:增强功能
2Reader reader = new FileReader("file.txt");
3reader = new BufferedReader(reader); // 添加缓冲功能

2. 适配器模式

java
1// 目的:接口转换
2InputStream is = new FileInputStream("file.txt");
3Reader reader = new InputStreamReader(is); // 字节流转字符流

3. 代理模式

java
1// 目的:控制访问
2UserService proxy = (UserService) Proxy.newProxyInstance(
3 UserService.class.getClassLoader(),
4 new Class[]{UserService.class},
5 new InvocationHandler() {
6 public Object invoke(Object proxy, Method method, Object[] args) {
7 // 前置处理
8 Object result = method.invoke(target, args);
9 // 后置处理
10 return result;
11 }
12 }
13);

4. 桥接模式

java
1// 目的:分离抽象和实现
2abstract class Shape {
3 protected Color color; // 桥接
4 abstract void draw();
5}

核心区别:

  • 装饰器:同接口,增强功能
  • 适配器:不同接口,转换接口
  • 代理:同接口,控制访问
  • 桥接:分离抽象,独立变化

14. 什么是外观模式?一般用在什么场景?

答案:

外观模式为复杂子系统提供一个统一的高层接口,简化调用。

实现示例:

java
1// 子系统1:CPU
2class CPU {
3 public void start() {
4 System.out.println("CPU started");
5 }
6
7 public void shutdown() {
8 System.out.println("CPU shutdown");
9 }
10}
11
12// 子系统2:内存
13class Memory {
14 public void load() {
15 System.out.println("Memory loaded");
16 }
17}
18
19// 子系统3:硬盘
20class HardDrive {
21 public void read() {
22 System.out.println("Hard drive reading");
23 }
24}
25
26// 外观类
27class ComputerFacade {
28 private CPU cpu;
29 private Memory memory;
30 private HardDrive hardDrive;
31
32 public ComputerFacade() {
33 this.cpu = new CPU();
34 this.memory = new Memory();
35 this.hardDrive = new HardDrive();
36 }
37
38 // 统一的启动接口
39 public void start() {
40 cpu.start();
41 memory.load();
42 hardDrive.read();
43 System.out.println("Computer started");
44 }
45
46 // 统一的关闭接口
47 public void shutdown() {
48 cpu.shutdown();
49 System.out.println("Computer shutdown");
50 }
51}
52
53// 使用
54public class Demo {
55 public static void main(String[] args) {
56 ComputerFacade computer = new ComputerFacade();
57 computer.start(); // 简单调用
58 computer.shutdown();
59 }
60}

使用场景:

  1. 简化复杂系统:为复杂子系统提供简单接口
  2. 分层架构:层与层之间的接口
  3. 降低耦合:客户端与子系统解耦

实际应用:

  • SLF4J日志外观
  • JDBC的DriverManager
  • Spring的各种Template类

15. 什么是享元模式?一般用在什么场景?

答案:

享元模式通过共享技术有效支持大量细粒度对象,减少内存开销。

实现示例:

java
1// 享元接口
2interface Shape {
3 void draw(int x, int y);
4}
5
6// 具体享元类
7class Circle implements Shape {
8 private String color; // 内部状态(共享)
9
10 public Circle(String color) {
11 this.color = color;
12 }
13
14 @Override
15 public void draw(int x, int y) { // 外部状态(不共享)
16 System.out.println("Drawing " + color + " circle at (" + x + ", " + y + ")");
17 }
18}
19
20// 享元工厂
21class ShapeFactory {
22 private static final Map<String, Shape> circleMap = new HashMap<>();
23
24 public static Shape getCircle(String color) {
25 Circle circle = (Circle) circleMap.get(color);
26
27 if (circle == null) {
28 circle = new Circle(color);
29 circleMap.put(color, circle);
30 System.out.println("Creating " + color + " circle");
31 }
32
33 return circle;
34 }
35}
36
37// 使用
38public class Demo {
39 public static void main(String[] args) {
40 String[] colors = {"Red", "Green", "Blue", "Red", "Green"};
41
42 for (int i = 0; i < 5; i++) {
43 Shape circle = ShapeFactory.getCircle(colors[i]);
44 circle.draw(i * 10, i * 20);
45 }
46
47 // 只创建了3个对象,而不是5个
48 }
49}

核心概念:

  • 内部状态:可共享的不变部分(如颜色)
  • 外部状态:不可共享的变化部分(如坐标)

使用场景:

  1. 大量相似对象:游戏中的子弹、树木
  2. 内存优化:减少对象创建数量
  3. 不变对象:对象状态不经常变化

实际应用:

java
1// String常量池
2String s1 = "hello";
3String s2 = "hello"; // 共享同一对象
4
5// Integer缓存(-128到127)
6Integer i1 = 100;
7Integer i2 = 100; // 共享同一对象
8
9// 数据库连接池

16. 什么是代理模式?一般用在什么场景?

答案:

代理模式为对象提供一个代理,控制对该对象的访问。

静态代理:

java
1// 接口
2interface UserService {
3 void save(String user);
4}
5
6// 真实对象
7class UserServiceImpl implements UserService {
8 @Override
9 public void save(String user) {
10 System.out.println("Saving user: " + user);
11 }
12}
13
14// 代理类
15class UserServiceProxy implements UserService {
16 private UserService target;
17
18 public UserServiceProxy(UserService target) {
19 this.target = target;
20 }
21
22 @Override
23 public void save(String user) {
24 System.out.println("Before save - logging");
25 target.save(user);
26 System.out.println("After save - logging");
27 }
28}
29
30// 使用
31UserService service = new UserServiceImpl();
32UserService proxy = new UserServiceProxy(service);
33proxy.save("John");

JDK动态代理:

java
1UserService service = new UserServiceImpl();
2
3UserService proxy = (UserService) Proxy.newProxyInstance(
4 service.getClass().getClassLoader(),
5 service.getClass().getInterfaces(),
6 new InvocationHandler() {
7 @Override
8 public Object invoke(Object proxy, Method method, Object[] args)
9 throws Throwable {
10 System.out.println("Before: " + method.getName());
11 Object result = method.invoke(service, args);
12 System.out.println("After: " + method.getName());
13 return result;
14 }
15 }
16);
17
18proxy.save("John");

CGLIB代理:

java
1class UserService {
2 public void save(String user) {
3 System.out.println("Saving: " + user);
4 }
5}
6
7Enhancer enhancer = new Enhancer();
8enhancer.setSuperclass(UserService.class);
9enhancer.setCallback(new MethodInterceptor() {
10 @Override
11 public Object intercept(Object obj, Method method, Object[] args,
12 MethodProxy proxy) throws Throwable {
13 System.out.println("Before");
14 Object result = proxy.invokeSuper(obj, args);
15 System.out.println("After");
16 return result;
17 }
18});
19
20UserService proxy = (UserService) enhancer.create();
21proxy.save("John");

使用场景:

  1. 远程代理:RPC、RMI
  2. 虚拟代理:延迟加载大对象
  3. 保护代理:权限控制
  4. 智能代理:日志、缓存、事务

实际应用:

  • Spring AOP
  • MyBatis Mapper接口
  • Feign远程调用

17. 什么是观察者模式?一般用在什么场景?

答案:

观察者模式定义对象间的一对多依赖,当一个对象状态改变时,所有依赖它的对象都会收到通知。

实现示例:

java
1// 观察者接口
2interface Observer {
3 void update(String message);
4}
5
6// 具体观察者
7class User implements Observer {
8 private String name;
9
10 public User(String name) {
11 this.name = name;
12 }
13
14 @Override
15 public void update(String message) {
16 System.out.println(name + " received: " + message);
17 }
18}
19
20// 主题(被观察者)
21class Subject {
22 private List<Observer> observers = new ArrayList<>();
23
24 // 添加观察者
25 public void attach(Observer observer) {
26 observers.add(observer);
27 }
28
29 // 移除观察者
30 public void detach(Observer observer) {
31 observers.remove(observer);
32 }
33
34 // 通知所有观察者
35 public void notifyObservers(String message) {
36 for (Observer observer : observers) {
37 observer.update(message);
38 }
39 }
40}
41
42// 具体主题
43class NewsAgency extends Subject {
44 public void publishNews(String news) {
45 System.out.println("Publishing news: " + news);
46 notifyObservers(news);
47 }
48}
49
50// 使用
51public class Demo {
52 public static void main(String[] args) {
53 NewsAgency agency = new NewsAgency();
54
55 User user1 = new User("Alice");
56 User user2 = new User("Bob");
57
58 agency.attach(user1);
59 agency.attach(user2);
60
61 agency.publishNews("Breaking News!");
62 }
63}

使用场景:

  1. 事件处理:GUI事件监听
  2. 消息通知:订阅发布系统
  3. 数据同步:模型-视图同步

实际应用:

java
1// Java内置支持
2java.util.Observable
3java.util.Observer
4
5// Spring事件
6ApplicationEventPublisher
7
8// MQ消息队列
9Kafka, RabbitMQ

18. 什么是迭代器模式?一般用在什么场景?

答案:

迭代器模式提供一种方法顺序访问聚合对象中的元素,而不暴露其内部表示。

实现示例:

java
1// 迭代器接口
2interface Iterator<T> {
3 boolean hasNext();
4 T next();
5}
6
7// 聚合接口
8interface Container<T> {
9 Iterator<T> getIterator();
10}
11
12// 具体聚合
13class BookCollection implements Container<String> {
14 private String[] books;
15 private int index = 0;
16
17 public BookCollection(int size) {
18 books = new String[size];
19 }
20
21 public void addBook(String book) {
22 if (index < books.length) {
23 books[index++] = book;
24 }
25 }
26
27 @Override
28 public Iterator<String> getIterator() {
29 return new BookIterator();
30 }
31
32 // 内部迭代器类
33 private class BookIterator implements Iterator<String> {
34 private int currentIndex = 0;
35
36 @Override
37 public boolean hasNext() {
38 return currentIndex < index;
39 }
40
41 @Override
42 public String next() {
43 if (hasNext()) {
44 return books[currentIndex++];
45 }
46 return null;
47 }
48 }
49}
50
51// 使用
52public class Demo {
53 public static void main(String[] args) {
54 BookCollection books = new BookCollection(3);
55 books.addBook("Design Patterns");
56 books.addBook("Clean Code");
57 books.addBook("Refactoring");
58
59 Iterator<String> iterator = books.getIterator();
60 while (iterator.hasNext()) {
61 System.out.println(iterator.next());
62 }
63 }
64}

使用场景:

  1. 聚合遍历:统一遍历接口
  2. 隐藏内部结构:不暴露实现细节
  3. 多种遍历方式:支持不同遍历策略

实际应用:

java
1// Java集合框架
2List<String> list = new ArrayList<>();
3Iterator<String> iterator = list.iterator();
4
5// for-each语法糖
6for (String item : list) {
7 // 内部使用迭代器
8}

19. 什么是模板方法模式?一般用在什么场景?

答案:

模板方法模式定义算法骨架,将某些步骤延迟到子类实现。

实现示例:

java
1// 抽象类
2abstract class DataProcessor {
3 // 模板方法:定义算法骨架
4 public final void process() {
5 readData();
6 processData();
7 saveData();
8 }
9
10 // 具体方法
11 private void readData() {
12 System.out.println("Reading data...");
13 }
14
15 // 抽象方法:由子类实现
16 protected abstract void processData();
17
18 // 钩子方法:可选重写
19 protected void saveData() {
20 System.out.println("Saving data...");
21 }
22}
23
24// 具体子类1
25class CSVDataProcessor extends DataProcessor {
26 @Override
27 protected void processData() {
28 System.out.println("Processing CSV data");
29 }
30}
31
32// 具体子类2
33class JSONDataProcessor extends DataProcessor {
34 @Override
35 protected void processData() {
36 System.out.println("Processing JSON data");
37 }
38
39 @Override
40 protected void saveData() {
41 System.out.println("Saving JSON to database");
42 }
43}
44
45// 使用
46public class Demo {
47 public static void main(String[] args) {
48 DataProcessor csv = new CSVDataProcessor();
49 csv.process();
50
51 System.out.println();
52
53 DataProcessor json = new JSONDataProcessor();
54 json.process();
55 }
56}

使用场景:

  1. 算法骨架固定:步骤固定,细节变化
  2. 代码复用:公共代码提取到父类
  3. 控制扩展:只允许特定步骤扩展

实际应用:

java
1// Servlet的service方法
2public abstract class HttpServlet {
3 public void service(HttpServletRequest req, HttpServletResponse resp) {
4 String method = req.getMethod();
5 if (method.equals("GET")) {
6 doGet(req, resp);
7 } else if (method.equals("POST")) {
8 doPost(req, resp);
9 }
10 }
11
12 protected abstract void doGet(HttpServletRequest req, HttpServletResponse resp);
13 protected abstract void doPost(HttpServletRequest req, HttpServletResponse resp);
14}
15
16// Spring的JdbcTemplate
17// MyBatis的BaseExecutor

20. 什么是命令模式?一般用在什么场景?

答案:

命令模式将请求封装为对象,从而可以参数化、队列化、记录请求。

实现示例:

java
1// 命令接口
2interface Command {
3 void execute();
4 void undo();
5}
6
7// 接收者:灯
8class Light {
9 public void on() {
10 System.out.println("Light is ON");
11 }
12
13 public void off() {
14 System.out.println("Light is OFF");
15 }
16}
17
18// 具体命令:开灯
19class LightOnCommand implements Command {
20 private Light light;
21
22 public LightOnCommand(Light light) {
23 this.light = light;
24 }
25
26 @Override
27 public void execute() {
28 light.on();
29 }
30
31 @Override
32 public void undo() {
33 light.off();
34 }
35}
36
37// 具体命令:关灯
38class LightOffCommand implements Command {
39 private Light light;
40
41 public LightOffCommand(Light light) {
42 this.light = light;
43 }
44
45 @Override
46 public void execute() {
47 light.off();
48 }
49
50 @Override
51 public void undo() {
52 light.on();
53 }
54}
55
56// 调用者:遥控器
57class RemoteControl {
58 private Command command;
59
60 public void setCommand(Command command) {
61 this.command = command;
62 }
63
64 public void pressButton() {
65 command.execute();
66 }
67
68 public void pressUndo() {
69 command.undo();
70 }
71}
72
73// 使用
74public class Demo {
75 public static void main(String[] args) {
76 Light light = new Light();
77 Command lightOn = new LightOnCommand(light);
78 Command lightOff = new LightOffCommand(light);
79
80 RemoteControl remote = new RemoteControl();
81
82 remote.setCommand(lightOn);
83 remote.pressButton(); // 开灯
84 remote.pressUndo(); // 撤销,关灯
85
86 remote.setCommand(lightOff);
87 remote.pressButton(); // 关灯
88 }
89}

使用场景:

  1. 撤销/重做:编辑器操作
  2. 队列请求:任务队列
  3. 记录日志:操作日志
  4. 宏命令:组合多个命令

实际应用:

java
1// Runnable接口
2Runnable task = () -> System.out.println("Task");
3new Thread(task).start();
4
5// Spring的JdbcTemplate回调
6// Struts2的Action

21. 什么是状态模式?一般用在什么场景?

答案:

状态模式允许对象在内部状态改变时改变其行为。

实现示例:

java
1// 状态接口
2interface State {
3 void handle(Context context);
4}
5
6// 具体状态:开始状态
7class StartState implements State {
8 @Override
9 public void handle(Context context) {
10 System.out.println("Starting...");
11 context.setState(new RunningState());
12 }
13}
14
15// 具体状态:运行状态
16class RunningState implements State {
17 @Override
18 public void handle(Context context) {
19 System.out.println("Running...");
20 context.setState(new StopState());
21 }
22}
23
24// 具体状态:停止状态
25class StopState implements State {
26 @Override
27 public void handle(Context context) {
28 System.out.println("Stopped.");
29 context.setState(null);
30 }
31}
32
33// 上下文类
34class Context {
35 private State state;
36
37 public Context() {
38 this.state = new StartState();
39 }
40
41 public void setState(State state) {
42 this.state = state;
43 }
44
45 public void request() {
46 if (state != null) {
47 state.handle(this);
48 }
49 }
50}
51
52// 使用
53public class Demo {
54 public static void main(String[] args) {
55 Context context = new Context();
56 context.request(); // Starting
57 context.request(); // Running
58 context.request(); // Stopped
59 }
60}

使用场景:

  1. 状态机:工作流、订单状态
  2. 条件分支复杂:替代大量if-else
  3. 状态转换:状态间有明确转换规则

实际应用:

  • TCP连接状态
  • 订单状态流转
  • 线程状态

22. 什么是策略模式?一般用在什么场景?

答案:

策略模式定义一系列算法,将每个算法封装起来,使它们可以互相替换。

实现示例:

java
1// 策略接口
2interface PaymentStrategy {
3 void pay(int amount);
4}
5
6// 具体策略:支付宝
7class AlipayStrategy implements PaymentStrategy {
8 @Override
9 public void pay(int amount) {
10 System.out.println("Paid " + amount + " using Alipay");
11 }
12}
13
14// 具体策略:微信
15class WeChatStrategy implements PaymentStrategy {
16 @Override
17 public void pay(int amount) {
18 System.out.println("Paid " + amount + " using WeChat");
19 }
20}
21
22// 具体策略:银行卡
23class BankCardStrategy implements PaymentStrategy {
24 @Override
25 public void pay(int amount) {
26 System.out.println("Paid " + amount + " using Bank Card");
27 }
28}
29
30// 上下文类
31class ShoppingCart {
32 private PaymentStrategy paymentStrategy;
33
34 public void setPaymentStrategy(PaymentStrategy strategy) {
35 this.paymentStrategy = strategy;
36 }
37
38 public void checkout(int amount) {
39 paymentStrategy.pay(amount);
40 }
41}
42
43// 使用
44public class Demo {
45 public static void main(String[] args) {
46 ShoppingCart cart = new ShoppingCart();
47
48 // 使用支付宝
49 cart.setPaymentStrategy(new AlipayStrategy());
50 cart.checkout(100);
51
52 // 切换为微信
53 cart.setPaymentStrategy(new WeChatStrategy());
54 cart.checkout(200);
55 }
56}

使用场景:

  1. 多种算法可选:支付方式、排序算法
  2. 避免if-else:替代复杂条件分支
  3. 算法独立变化:算法可独立扩展

实际应用:

java
1// Comparator
2Collections.sort(list, new Comparator<String>() {
3 public int compare(String s1, String s2) {
4 return s1.compareTo(s2);
5 }
6});
7
8// ThreadPoolExecutor的拒绝策略
9RejectedExecutionHandler

23. 什么是责任链模式?一般用在什么场景?

答案:

责任链模式将请求沿着处理者链传递,直到有处理者处理它。

实现示例:

java
1// 抽象处理者
2abstract class Handler {
3 protected Handler nextHandler;
4
5 public void setNext(Handler handler) {
6 this.nextHandler = handler;
7 }
8
9 public abstract void handleRequest(int level);
10}
11
12// 具体处理者:经理
13class Manager extends Handler {
14 @Override
15 public void handleRequest(int level) {
16 if (level <= 1) {
17 System.out.println("Manager handled request level " + level);
18 } else if (nextHandler != null) {
19 nextHandler.handleRequest(level);
20 }
21 }
22}
23
24// 具体处理者:总监
25class Director extends Handler {
26 @Override
27 public void handleRequest(int level) {
28 if (level <= 2) {
29 System.out.println("Director handled request level " + level);
30 } else if (nextHandler != null) {
31 nextHandler.handleRequest(level);
32 }
33 }
34}
35
36// 具体处理者:CEO
37class CEO extends Handler {
38 @Override
39 public void handleRequest(int level) {
40 System.out.println("CEO handled request level " + level);
41 }
42}
43
44// 使用
45public class Demo {
46 public static void main(String[] args) {
47 Handler manager = new Manager();
48 Handler director = new Director();
49 Handler ceo = new CEO();
50
51 // 构建责任链
52 manager.setNext(director);
53 director.setNext(ceo);
54
55 // 发起请求
56 manager.handleRequest(1); // Manager处理
57 manager.handleRequest(2); // Director处理
58 manager.handleRequest(3); // CEO处理
59 }
60}

使用场景:

  1. 审批流程:请假、报销审批
  2. 过滤器链:Servlet Filter
  3. 异常处理:多级异常捕获

实际应用:

java
1// Servlet Filter链
2FilterChain
3
4// Netty的ChannelPipeline
5pipeline.addLast(new Handler1());
6pipeline.addLast(new Handler2());
7
8// Spring Security过滤器链

24. 什么是中介者模式?一般用在什么场景?

答案:

中介者模式用一个中介对象封装一系列对象的交互,降低对象间的耦合。

实现示例:

java
1// 中介者接口
2interface ChatMediator {
3 void sendMessage(String message, User user);
4 void addUser(User user);
5}
6
7// 具体中介者
8class ChatRoom implements ChatMediator {
9 private List<User> users = new ArrayList<>();
10
11 @Override
12 public void addUser(User user) {
13 users.add(user);
14 }
15
16 @Override
17 public void sendMessage(String message, User sender) {
18 for (User user : users) {
19 // 不发给发送者自己
20 if (user != sender) {
21 user.receive(message);
22 }
23 }
24 }
25}
26
27// 同事类
28class User {
29 private String name;
30 private ChatMediator mediator;
31
32 public User(String name, ChatMediator mediator) {
33 this.name = name;
34 this.mediator = mediator;
35 }
36
37 public void send(String message) {
38 System.out.println(name + " sends: " + message);
39 mediator.sendMessage(message, this);
40 }
41
42 public void receive(String message) {
43 System.out.println(name + " received: " + message);
44 }
45}
46
47// 使用
48public class Demo {
49 public static void main(String[] args) {
50 ChatMediator chatRoom = new ChatRoom();
51
52 User alice = new User("Alice", chatRoom);
53 User bob = new User("Bob", chatRoom);
54 User charlie = new User("Charlie", chatRoom);
55
56 chatRoom.addUser(alice);
57 chatRoom.addUser(bob);
58 chatRoom.addUser(charlie);
59
60 alice.send("Hello everyone!");
61 }
62}

使用场景:

  1. 复杂交互:多对象互相通信
  2. 降低耦合:对象间不直接引用
  3. 集中控制:统一管理交互逻辑

实际应用:

  • MVC中的Controller
  • 聊天室服务器
  • 机场控制塔

25. 什么是访问者模式?一般用在什么场景?

答案:

访问者模式将数据结构与操作分离,在不改变数据结构的前提下添加新操作。

实现示例:

java
1// 访问者接口
2interface Visitor {
3 void visit(Book book);
4 void visit(Fruit fruit);
5}
6
7// 元素接口
8interface Element {
9 void accept(Visitor visitor);
10}
11
12// 具体元素:书
13class Book implements Element {
14 private String name;
15 private double price;
16
17 public Book(String name, double price) {
18 this.name = name;
19 this.price = price;
20 }
21
22 public String getName() { return name; }
23 public double getPrice() { return price; }
24
25 @Override
26 public void accept(Visitor visitor) {
27 visitor.visit(this);
28 }
29}
30
31// 具体元素:水果
32class Fruit implements Element {
33 private String name;
34 private double weight;
35 private double pricePerKg;
36
37 public Fruit(String name, double weight, double pricePerKg) {
38 this.name = name;
39 this.weight = weight;
40 this.pricePerKg = pricePerKg;
41 }
42
43 public String getName() { return name; }
44 public double getWeight() { return weight; }
45 public double getPricePerKg() { return pricePerKg; }
46
47 @Override
48 public void accept(Visitor visitor) {
49 visitor.visit(this);
50 }
51}
52
53// 具体访问者:计算价格
54class PriceCalculator implements Visitor {
55 private double totalPrice = 0;
56
57 @Override
58 public void visit(Book book) {
59 totalPrice += book.getPrice();
60 System.out.println("Book: " + book.getName() + " - $" + book.getPrice());
61 }
62
63 @Override
64 public void visit(Fruit fruit) {
65 double price = fruit.getWeight() * fruit.getPricePerKg();
66 totalPrice += price;
67 System.out.println("Fruit: " + fruit.getName() + " - $" + price);
68 }
69
70 public double getTotalPrice() {
71 return totalPrice;
72 }
73}
74
75// 使用
76public class Demo {
77 public static void main(String[] args) {
78 List<Element> items = new ArrayList<>();
79 items.add(new Book("Design Patterns", 50));
80 items.add(new Fruit("Apple", 2, 5));
81 items.add(new Book("Clean Code", 45));
82
83 PriceCalculator calculator = new PriceCalculator();
84 for (Element item : items) {
85 item.accept(calculator);
86 }
87
88 System.out.println("Total: $" + calculator.getTotalPrice());
89 }
90}

使用场景:

  1. 数据结构稳定:结构不变,操作多变
  2. 多种操作:需要对元素执行多种不同操作
  3. 分离关注点:数据与算法分离

实际应用:

  • 编译器的AST遍历
  • XML文档处理
  • 文件系统操作

26. 什么是备忘录模式?一般用在什么场景?

答案:

备忘录模式在不破坏封装的前提下,捕获对象的内部状态并保存,以便后续恢复。

实现示例:

java
1// 备忘录类
2class Memento {
3 private String state;
4
5 public Memento(String state) {
6 this.state = state;
7 }
8
9 public String getState() {
10 return state;
11 }
12}
13
14// 原发器
15class Editor {
16 private String content;
17
18 public void setContent(String content) {
19 this.content = content;
20 }
21
22 public String getContent() {
23 return content;
24 }
25
26 // 保存状态
27 public Memento save() {
28 return new Memento(content);
29 }
30
31 // 恢复状态
32 public void restore(Memento memento) {
33 this.content = memento.getState();
34 }
35}
36
37// 管理者
38class History {
39 private Stack<Memento> mementos = new Stack<>();
40
41 public void push(Memento memento) {
42 mementos.push(memento);
43 }
44
45 public Memento pop() {
46 return mementos.pop();
47 }
48}
49
50// 使用
51Editor editor = new Editor();
52History history = new History();
53
54editor.setContent("Version 1");
55history.push(editor.save());
56
57editor.setContent("Version 2");
58history.push(editor.save());
59
60editor.setContent("Version 3");
61
62// 撤销
63editor.restore(history.pop());
64System.out.println(editor.getContent()); // Version 2

使用场景:

  • 撤销/重做功能
  • 事务回滚
  • 游戏存档

27. 什么是单一职责原则?

答案:

单一职责原则(SRP):一个类应该只有一个引起它变化的原因。

核心思想:

  • 一个类只负责一项职责
  • 降低类的复杂度
  • 提高可读性和可维护性

示例:

java
1// 违反SRP:一个类承担多个职责
2class User {
3 private String name;
4
5 // 职责1:用户数据管理
6 public void setName(String name) {
7 this.name = name;
8 }
9
10 // 职责2:数据库操作
11 public void save() {
12 // 保存到数据库
13 }
14
15 // 职责3:邮件发送
16 public void sendEmail() {
17 // 发送邮件
18 }
19}
20
21// 符合SRP:职责分离
22class User {
23 private String name;
24 public void setName(String name) { this.name = name; }
25}
26
27class UserRepository {
28 public void save(User user) { /* 保存 */ }
29}
30
31class EmailService {
32 public void sendEmail(User user) { /* 发送 */ }
33}

28. 什么是开闭原则?

答案:

开闭原则(OCP):软件实体应该对扩展开放,对修改关闭。

核心思想:

  • 通过扩展实现变化,而不是修改现有代码
  • 使用抽象和多态
  • 提高系统稳定性

示例:

java
1// 违反OCP:需要修改代码添加新功能
2class Calculator {
3 public double calculate(String type, double a, double b) {
4 if (type.equals("add")) {
5 return a + b;
6 } else if (type.equals("subtract")) {
7 return a - b;
8 }
9 // 添加新运算需要修改此方法
10 return 0;
11 }
12}
13
14// 符合OCP:通过扩展添加新功能
15interface Operation {
16 double calculate(double a, double b);
17}
18
19class Add implements Operation {
20 public double calculate(double a, double b) {
21 return a + b;
22 }
23}
24
25class Subtract implements Operation {
26 public double calculate(double a, double b) {
27 return a - b;
28 }
29}
30
31// 添加新运算只需新增类,无需修改现有代码
32class Multiply implements Operation {
33 public double calculate(double a, double b) {
34 return a * b;
35 }
36}

29. 什么是里氏替换原则?

答案:

里氏替换原则(LSP):子类对象能够替换父类对象,程序行为不变。

核心思想:

  • 子类必须完全实现父类的方法
  • 子类可以有自己的特性
  • 覆盖父类方法时,输入参数可以放宽,输出结果应该收紧

示例:

java
1// 违反LSP
2class Rectangle {
3 protected int width;
4 protected int height;
5
6 public void setWidth(int width) { this.width = width; }
7 public void setHeight(int height) { this.height = height; }
8 public int getArea() { return width * height; }
9}
10
11class Square extends Rectangle {
12 @Override
13 public void setWidth(int width) {
14 this.width = width;
15 this.height = width; // 破坏了父类行为
16 }
17}
18
19// 符合LSP:使用组合而非继承
20interface Shape {
21 int getArea();
22}
23
24class Rectangle implements Shape {
25 private int width;
26 private int height;
27
28 public int getArea() { return width * height; }
29}
30
31class Square implements Shape {
32 private int side;
33
34 public int getArea() { return side * side; }
35}

30. 什么是接口隔离原则?

答案:

接口隔离原则(ISP):客户端不应该依赖它不需要的接口。

核心思想:

  • 接口应该小而专一
  • 避免臃肿的接口
  • 一个类对另一个类的依赖应该建立在最小接口上

示例:

java
1// 违反ISP:臃肿的接口
2interface Worker {
3 void work();
4 void eat();
5 void sleep();
6}
7
8class Human implements Worker {
9 public void work() { /* 工作 */ }
10 public void eat() { /* 吃饭 */ }
11 public void sleep() { /* 睡觉 */ }
12}
13
14class Robot implements Worker {
15 public void work() { /* 工作 */ }
16 public void eat() { /* 机器人不需要 */ }
17 public void sleep() { /* 机器人不需要 */ }
18}
19
20// 符合ISP:接口分离
21interface Workable {
22 void work();
23}
24
25interface Eatable {
26 void eat();
27}
28
29interface Sleepable {
30 void sleep();
31}
32
33class Human implements Workable, Eatable, Sleepable {
34 public void work() { /* 工作 */ }
35 public void eat() { /* 吃饭 */ }
36 public void sleep() { /* 睡觉 */ }
37}
38
39class Robot implements Workable {
40 public void work() { /* 工作 */ }
41}

31. 什么是依赖倒置原则?

答案:

依赖倒置原则(DIP):高层模块不应该依赖低层模块,两者都应该依赖抽象。

核心思想:

  • 面向接口编程,不面向实现编程
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 降低耦合度

示例:

java
1// 违反DIP:高层依赖低层具体实现
2class MySQLDatabase {
3 public void connect() {
4 System.out.println("MySQL connected");
5 }
6}
7
8class UserService {
9 private MySQLDatabase database = new MySQLDatabase();
10
11 public void getUser() {
12 database.connect();
13 // 获取用户
14 }
15}
16
17// 符合DIP:依赖抽象
18interface Database {
19 void connect();
20}
21
22class MySQLDatabase implements Database {
23 public void connect() {
24 System.out.println("MySQL connected");
25 }
26}
27
28class MongoDatabase implements Database {
29 public void connect() {
30 System.out.println("MongoDB connected");
31 }
32}
33
34class UserService {
35 private Database database;
36
37 // 依赖注入
38 public UserService(Database database) {
39 this.database = database;
40 }
41
42 public void getUser() {
43 database.connect();
44 // 获取用户
45 }
46}

32. 什么是迪米特法则?

答案:

迪米特法则(LoD):一个对象应该对其他对象有最少的了解,只与直接的朋友通信。

核心思想:

  • 降低类之间的耦合
  • 类只与直接朋友交互
  • 不要和陌生人说话

示例:

java
1// 违反迪米特法则
2class Engine {
3 public void start() {
4 System.out.println("Engine started");
5 }
6}
7
8class Car {
9 private Engine engine;
10
11 public Engine getEngine() {
12 return engine;
13 }
14}
15
16class Driver {
17 public void drive(Car car) {
18 // 直接访问Car的内部对象
19 car.getEngine().start();
20 }
21}
22
23// 符合迪米特法则
24class Car {
25 private Engine engine;
26
27 // 封装内部细节
28 public void start() {
29 engine.start();
30 }
31}
32
33class Driver {
34 public void drive(Car car) {
35 // 只与Car交互
36 car.start();
37 }
38}

33. 谈谈你了解的最常见的几种设计模式,说说他们的应用场景

答案:

1. 单例模式

  • 场景:数据库连接池、配置管理器、日志工具
  • 优势:全局唯一实例,节省资源

2. 工厂模式

  • 场景:对象创建逻辑复杂、需要解耦创建和使用
  • 优势:封装创建逻辑,易于扩展

3. 代理模式

  • 场景:Spring AOP、RPC调用、权限控制
  • 优势:在不修改原对象的情况下增强功能

4. 观察者模式

  • 场景:事件监听、消息队列、MVC架构
  • 优势:松耦合的事件通知机制

5. 策略模式

  • 场景:支付方式选择、排序算法切换
  • 优势:算法可替换,避免大量if-else

6. 模板方法模式

  • 场景:Servlet、Spring JdbcTemplate
  • 优势:复用公共代码,子类只实现差异部分

7. 装饰器模式

  • 场景:Java IO流、动态添加功能
  • 优势:灵活扩展对象功能

8. 适配器模式

  • 场景:系统集成、接口转换
  • 优势:让不兼容的接口协同工作

34. 请用一句话概括,什么是设计模式?为什么要用?

答案:

什么是: 设计模式是软件开发中反复出现的问题的经验性解决方案。

为什么用:

  1. 提高代码质量:可读性、可维护性、可扩展性
  2. 降低开发成本:复用成熟方案,减少试错
  3. 统一开发语言:团队沟通更高效
  4. 应对变化:让系统更容易适应需求变化
  5. 最佳实践:站在巨人的肩膀上

一句话总结: 设计模式是前人智慧的结晶,帮助我们写出高质量、易维护、可扩展的代码。

35. 你认为好的代码应该是什么样的?

答案:

1. 可读性强

  • 命名清晰、注释恰当
  • 代码结构清晰
  • 遵循编码规范

2. 可维护性好

  • 低耦合、高内聚
  • 职责单一
  • 易于修改和扩展

3. 可测试性高

  • 模块化设计
  • 依赖可注入
  • 易于编写单元测试

4. 性能优秀

  • 算法高效
  • 资源利用合理
  • 无明显性能瓶颈

5. 健壮性强

  • 异常处理完善
  • 边界条件考虑周全
  • 容错能力强

6. 遵循原则

  • SOLID原则
  • DRY(Don't Repeat Yourself)
  • KISS(Keep It Simple, Stupid)
  • YAGNI(You Aren't Gonna Need It)

代码示例:

java
1// 好的代码
2public class OrderService {
3 private final OrderRepository orderRepository;
4 private final PaymentService paymentService;
5
6 public OrderService(OrderRepository orderRepository,
7 PaymentService paymentService) {
8 this.orderRepository = orderRepository;
9 this.paymentService = paymentService;
10 }
11
12 public Order createOrder(OrderRequest request) {
13 validateRequest(request);
14 Order order = buildOrder(request);
15 orderRepository.save(order);
16 paymentService.processPayment(order);
17 return order;
18 }
19
20 private void validateRequest(OrderRequest request) {
21 if (request == null || request.getItems().isEmpty()) {
22 throw new IllegalArgumentException("Invalid order request");
23 }
24 }
25
26 private Order buildOrder(OrderRequest request) {
27 // 构建订单逻辑
28 return new Order();
29 }
30}

36. 什么是合成复用原则?

答案:

合成复用原则(CRP):优先使用组合/聚合,而不是继承来达到复用目的。

核心思想:

  • 继承是白盒复用,组合是黑盒复用
  • 继承破坏封装性,组合保持封装性
  • 继承是静态的,组合是动态的

示例:

java
1// 使用继承(不推荐)
2class Animal {
3 public void eat() {
4 System.out.println("Eating");
5 }
6}
7
8class Bird extends Animal {
9 public void fly() {
10 System.out.println("Flying");
11 }
12}
13
14class Penguin extends Bird {
15 // 问题:企鹅不会飞,但继承了fly方法
16 @Override
17 public void fly() {
18 throw new UnsupportedOperationException();
19 }
20}
21
22// 使用组合(推荐)
23interface Eatable {
24 void eat();
25}
26
27interface Flyable {
28 void fly();
29}
30
31class EatBehavior implements Eatable {
32 public void eat() {
33 System.out.println("Eating");
34 }
35}
36
37class FlyBehavior implements Flyable {
38 public void fly() {
39 System.out.println("Flying");
40 }
41}
42
43class Bird {
44 private Eatable eatBehavior;
45 private Flyable flyBehavior;
46
47 public Bird(Eatable eatBehavior, Flyable flyBehavior) {
48 this.eatBehavior = eatBehavior;
49 this.flyBehavior = flyBehavior;
50 }
51
52 public void eat() {
53 eatBehavior.eat();
54 }
55
56 public void fly() {
57 if (flyBehavior != null) {
58 flyBehavior.fly();
59 }
60 }
61}
62
63// 企鹅只有吃的行为,没有飞的行为
64Bird penguin = new Bird(new EatBehavior(), null);

优势:

  • 更灵活:运行时可以改变行为
  • 更松耦合:减少类之间的依赖
  • 更易扩展:添加新功能不影响现有代码

学习指南

核心要点:

  • 设计模式分类和应用场景
  • SOLID 设计原则
  • 常见设计模式的实现原理
  • 设计模式在实际项目中的应用

学习路径建议:

  1. 掌握 SOLID 设计原则
  2. 熟悉三大类设计模式的特征
  3. 深入理解常见设计模式的实现
  4. 学习在实际项目中应用设计模式
forum

评论区 / Comments