Java 设计模式面试题(完整版·可直接背诵)
目录
- [1. 设计模式三大分类](#1. 设计模式三大分类)
- [2. 单例模式](#2. 单例模式)
- [3. 工厂模式 / 抽象工厂模式](#3. 工厂模式 / 抽象工厂模式)
- [4. 代理模式(静态+JDK+CGLib)](#4. 代理模式(静态+JDK+CGLib))
1. 设计模式三大分类
创建型(5种)
对象怎么创建
工厂方法、抽象工厂、单例、建造者、原型
结构型(7种)
类/对象怎么组合
适配器、装饰器、代理、外观、桥接、组合、享元
行为型(11种)
对象之间怎么通信
策略、模板方法、观察者、迭代器、责任链、命令、备忘录、状态、访问者、中介者、解释器
2. 单例模式
定义
确保一个类全局只有一个实例,自己实例化,对外提供统一访问点。
适用场景
线程池、缓存、日志对象、配置加载、打印机、驱动、连接池。
特点
- 只有一个实例
- 构造器私有
- 自行实例化
- 全局访问
四大原则
- 构造方法私有
- 静态方法返回实例
- 多线程安全
- 反序列化不重建对象
实现方式(高频面试)
① 饿汉式(静态常量)
类加载就创建,天生线程安全
java
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
优点:简单、线程安全
缺点:可能浪费内存
② 饿汉式(静态代码块)
java
public class Singleton {
private static Singleton INSTANCE;
static { INSTANCE = new Singleton(); }
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
③ 懒汉式(线程不安全)
用到才创建,但多线程不安全。
④ 双重检查锁 DCL(推荐)
java
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) instance = new Singleton();
}
}
return instance;
}
}
关键点:volatile 禁止指令重排
⑤ 静态内部类(最优)
java
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
⑥ 枚举单例(最安全)
java
public enum Singleton {
INSTANCE;
}
优点:防反射、防反序列化、天生线程安全
3. 工厂模式 / 抽象工厂模式
工厂方法模式
一个工厂生产一种产品。
结构
- 抽象产品(Fruit)
- 具体产品(Apple、Pear)
- 抽象工厂(FruitFactory)
- 具体工厂(AppleFactory、PearFactory)
优点
- 解耦:创建与使用分离
- 符合开闭原则
缺点
产品多 → 工厂类爆炸
抽象工厂模式
一个工厂生产一系列相关产品(产品族)。
示例:手机工厂 → 生产 CPU + 屏幕
结构
- 抽象产品族:CPU、Screen
- 具体产品:Cpu650/Cpu825、Screen5/Screen6
- 抽象工厂:PhoneFactory
- 具体工厂:XiaoMiFactory、HongMiFactory
优点
- 统一管理系列产品
- 保证产品兼容性
- 一定程度符合开闭
缺点
增加新产品 → 要改所有工厂(违反开闭)
三种工厂总结
- 简单工厂:产品固定、少
- 工厂方法:单一产品、可扩展
- 抽象工厂:产品族、系列化
4. 代理模式(静态+JDK+CGLib)
定义
为对象提供代理对象 ,控制原对象访问。
作用:中介、增强、隔离、日志、事务、权限。
分类
- 静态代理
- 动态代理(JDK、CGLib)
静态代理
编译期就生成代理类
java
public interface BuyHouse { void buyHouse(); }
public class BuyHouseImpl implements BuyHouse {
public void buyHouse() { System.out.println("买房"); }
}
public class BuyHouseProxy implements BuyHouse {
private BuyHouse target;
public BuyHouseProxy(BuyHouse target) { this.target = target; }
public void buyHouse() {
System.out.println("前");
target.buyHouse();
System.out.println("后");
}
}
优点:简单
缺点:每个接口都要写代理类,维护爆炸
JDK 动态代理
基于接口
java
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) { this.target = target; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前");
Object res = method.invoke(target, args);
System.out.println("后");
return res;
}
}
// 使用
BuyHouse proxy = (BuyHouse) Proxy.newProxyInstance(
classLoader,
new Class[]{BuyHouse.class},
new DynamicProxyHandler(real)
);
优点:不用写代理类
缺点:必须有接口
CGLib 动态代理
基于继承 ,生成子类代理
无需接口。
java
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) { this.target = target; }
public Object intercept(Object o, Method m, Object[] args, MethodProxy mp) throws Throwable {
System.out.println("前");
Object res = mp.invokeSuper(o, args);
System.out.println("后");
return res;
}
}
优点:无接口也能代理
缺点:不能代理 final 类/final 方法
三种代理对比
| 代理 | 原理 | 要求 | 适用 |
|---|---|---|---|
| 静态代理 | 编码实现 | 接口 | 简单、少量 |
| JDK动态代理 | 接口+反射 | 必须接口 | Spring AOP 默认 |
| CGLib | 继承+字节码 | 无接口 | 类无接口 |