01.08 Java基础篇|设计模式深度解析
导读
- 目标:深入理解23种设计模式,掌握设计原则,能够灵活运用设计模式解决实际问题。
- 适用场景:代码重构、架构设计、面试准备。
设计原则
SOLID原则
- S:单一职责原则(SRP)
- O:开闭原则(OCP)
- L:里氏替换原则(LSP)
- I:接口隔离原则(ISP)
- D:依赖倒置原则(DIP)
创建型模式
1. 单例模式(Singleton)
定义:确保一个类只有一个实例,并提供一个全局访问点。
实现方式:
- 饿汉式
- 懒汉式(双重检查)
- 静态内部类
- 枚举
完整实现示例:
方式1:饿汉式(线程安全,但非延迟加载)
java
public class EagerSingleton {
// 类加载时就创建实例
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
// 防止反射创建实例
if (instance != null) {
throw new RuntimeException("Singleton instance already exists");
}
}
public static EagerSingleton getInstance() {
return instance;
}
}
方式2:懒汉式 - 双重检查锁定(线程安全,延迟加载)
java
public class LazySingleton {
private volatile static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
为什么需要volatile?
- 防止指令重排序 :
new LazySingleton()不是原子操作,可能发生重排序 - 保证可见性:确保多线程环境下所有线程都能看到最新的instance值
方式3:静态内部类(推荐,线程安全,延迟加载)
java
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
// 静态内部类在第一次使用时才加载
private static class SingletonHolder {
private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.instance;
}
}
优点:
- 线程安全:由JVM类加载机制保证
- 延迟加载:只有在调用getInstance()时才加载内部类
- 无需同步:性能好
方式4:枚举(最推荐,防止反射和序列化破坏)
java
public enum EnumSingleton {
INSTANCE;
private String data;
public void setData(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void doSomething() {
System.out.println("Singleton doing something");
}
}
// 使用
EnumSingleton.INSTANCE.doSomething();
枚举单例的优势:
- 线程安全:枚举实例由JVM保证唯一性
- 防止反射破坏:枚举类没有无参构造器
- 防止序列化破坏:枚举的序列化机制保证唯一性
- 代码简洁:无需手动实现getInstance()方法
应用场景:
- 配置类(如数据库配置、系统配置)
- 连接池(数据库连接池、HTTP连接池)
- 线程池(ExecutorService)
- 日志记录器(Logger)
- 缓存管理器
Spring中的单例:
java
@Component
@Scope("singleton") // 默认就是单例
public class ConfigService {
// Spring容器保证单例
}
2. 工厂模式(Factory)
注意 :工厂模式的完整实现示例请参考 01.03 Java基础篇|面向对象核心与设计实践 中的"常见设计模式深度解析"章节。
类型:
- 简单工厂(Simple Factory)
- 工厂方法(Factory Method)
- 抽象工厂(Abstract Factory)
简单工厂示例:
java
// 产品接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体产品
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount);
}
}
public class WeChatPayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount);
}
}
// 简单工厂
public class PaymentFactory {
public static PaymentStrategy create(String type) {
return switch (type) {
case "alipay" -> new AlipayStrategy();
case "wechat" -> new WeChatPayStrategy();
default -> throw new IllegalArgumentException("Unknown payment type: " + type);
};
}
}
// 使用
PaymentStrategy strategy = PaymentFactory.create("alipay");
strategy.pay(100.0);
工厂方法模式:
java
// 工厂接口
public interface PaymentFactory {
PaymentStrategy createPayment();
}
// 具体工厂
public class AlipayFactory implements PaymentFactory {
@Override
public PaymentStrategy createPayment() {
return new AlipayStrategy();
}
}
public class WeChatPayFactory implements PaymentFactory {
@Override
public PaymentStrategy createPayment() {
return new WeChatPayStrategy();
}
}
应用场景:
- 对象创建逻辑复杂
- 需要解耦创建和使用
- 需要支持扩展新类型
- 需要统一管理对象创建
3. 建造者模式(Builder)
注意 :建造者模式的完整实现示例请参考 01.03 Java基础篇|面向对象核心与设计实践 中的"常见设计模式深度解析"章节。
定义:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
核心思想:
- 将复杂对象的构建步骤分解
- 通过链式调用设置参数
- 在build()方法中完成最终构建和验证
简单示例:
java
public class Computer {
private String cpu;
private String memory;
private String disk;
private String display;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.memory = builder.memory;
this.disk = builder.disk;
this.display = builder.display;
}
public static class Builder {
private String cpu;
private String memory;
private String disk;
private String display;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder memory(String memory) {
this.memory = memory;
return this;
}
public Builder disk(String disk) {
this.disk = disk;
return this;
}
public Builder display(String display) {
this.display = display;
return this;
}
public Computer build() {
// 构建时验证
if (cpu == null || memory == null) {
throw new IllegalStateException("CPU and Memory are required");
}
return new Computer(this);
}
}
}
// 使用
Computer computer = new Computer.Builder()
.cpu("Intel i7")
.memory("16GB")
.disk("512GB SSD")
.display("27寸")
.build();
应用场景:
- 对象构建过程复杂,参数多
- 参数可选,需要灵活组合
- 需要链式调用,提升代码可读性
- 需要构建时验证参数
结构型模式
1. 适配器模式(Adapter)
定义:将一个类的接口转换成客户希望的另一个接口,使原本不兼容的类可以一起工作。
类型:
- 类适配器(通过继承实现)
- 对象适配器(通过组合实现,推荐)
完整实现示例:
场景:第三方支付接口适配
java
// 目标接口(客户端期望的接口)
public interface PaymentProcessor {
void processPayment(double amount);
String getPaymentMethod();
}
// 被适配的类(第三方库,接口不兼容)
public class ThirdPartyPayment {
public void pay(double amount, String currency) {
System.out.println("Third party payment: " + amount + " " + currency);
}
public String getType() {
return "ThirdParty";
}
}
// 适配器(对象适配器方式)
public class PaymentAdapter implements PaymentProcessor {
private ThirdPartyPayment thirdPartyPayment;
public PaymentAdapter(ThirdPartyPayment thirdPartyPayment) {
this.thirdPartyPayment = thirdPartyPayment;
}
@Override
public void processPayment(double amount) {
// 适配:调用第三方接口,使用默认货币
thirdPartyPayment.pay(amount, "CNY");
}
@Override
public String getPaymentMethod() {
// 适配:转换方法名
return thirdPartyPayment.getType();
}
}
// 使用
PaymentProcessor processor = new PaymentAdapter(new ThirdPartyPayment());
processor.processPayment(100.0);
类适配器方式(通过继承)
java
// 类适配器:通过继承被适配类
public class PaymentClassAdapter extends ThirdPartyPayment implements PaymentProcessor {
@Override
public void processPayment(double amount) {
super.pay(amount, "CNY");
}
@Override
public String getPaymentMethod() {
return super.getType();
}
}
应用场景:
- 接口不兼容:需要使用现有类,但接口不匹配
- 第三方库集成:集成第三方SDK时接口不匹配
- 遗留系统改造:改造旧系统时保持兼容性
- 统一接口:将多个不同接口统一为同一接口
Java中的适配器模式:
Arrays.asList():将数组适配为ListInputStreamReader:将字节流适配为字符流
2. 装饰器模式(Decorator)
定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更灵活。
核心思想:
- 通过组合而非继承扩展功能
- 可以动态地添加或移除功能
- 避免类爆炸问题
完整实现示例:
场景:咖啡加料系统
java
// 组件接口
public interface Coffee {
String getDescription();
double getCost();
}
// 具体组件
public class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double getCost() {
return 5.0;
}
}
// 装饰器抽象类
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return coffee.getDescription();
}
@Override
public double getCost() {
return coffee.getCost();
}
}
// 具体装饰器
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
@Override
public double getCost() {
return coffee.getCost() + 2.0;
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Sugar";
}
@Override
public double getCost() {
return coffee.getCost() + 1.0;
}
}
// 使用:可以任意组合装饰器
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription()); // "Simple Coffee, Milk, Sugar"
System.out.println(coffee.getCost()); // 8.0
Java IO中的装饰器模式:
java
// Java IO流就是装饰器模式的典型应用
InputStream inputStream = new FileInputStream("file.txt");
BufferedInputStream buffered = new BufferedInputStream(inputStream);
DataInputStream data = new DataInputStream(buffered);
// 每一层都装饰了前一层,添加了新的功能
装饰器模式 vs 继承:
| 特性 | 装饰器模式 | 继承 |
|---|---|---|
| 扩展方式 | 组合 | 继承 |
| 灵活性 | 运行时动态组合 | 编译时确定 |
| 类数量 | 较少(可组合) | 较多(类爆炸) |
| 功能叠加 | 可以任意叠加 | 单继承限制 |
应用场景:
- 动态扩展功能:需要在运行时添加功能
- 避免类爆炸:功能组合多,用继承会产生大量类
- Java IO流:
BufferedInputStream、DataInputStream等 - Java Servlet:
HttpServletRequestWrapper等
3. 代理模式(Proxy)
定义:为其他对象提供一种代理以控制对这个对象的访问。
类型:
- 静态代理:代理类手动编写
- JDK动态代理:基于接口,使用
Proxy类 - CGLIB代理:基于继承,使用字节码技术
完整实现示例:
静态代理
java
// 接口
public interface UserService {
void save();
void delete();
}
// 实现类
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
}
// 静态代理类
public class UserServiceProxy implements UserService {
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void save() {
System.out.println("前置处理:开启事务");
try {
target.save();
System.out.println("后置处理:提交事务");
} catch (Exception e) {
System.out.println("异常处理:回滚事务");
throw e;
}
}
@Override
public void delete() {
System.out.println("前置处理:开启事务");
try {
target.delete();
System.out.println("后置处理:提交事务");
} catch (Exception e) {
System.out.println("异常处理:回滚事务");
throw e;
}
}
}
// 使用
UserService service = new UserServiceProxy(new UserServiceImpl());
service.save();
JDK动态代理(基于接口)
java
// 代理工厂
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理:" + method.getName());
Object result = method.invoke(target, args);
System.out.println("后置处理:" + method.getName());
return result;
}
}
);
}
}
// 使用
UserService service = new UserServiceImpl();
UserService proxy = (UserService) new ProxyFactory(service).getProxyInstance();
proxy.save();
JDK动态代理原理:
- 通过
Proxy.newProxyInstance()创建代理对象 - 代理对象实现了目标接口的所有方法
- 方法调用时,会转发到
InvocationHandler.invoke() - 在
invoke()中可以添加增强逻辑
JDK动态代理的限制:
- 只能代理接口,不能代理类
- 目标类必须实现接口
CGLIB代理(基于继承,需要引入依赖)
java
// 目标类(不需要实现接口)
public class UserService {
public void save() {
System.out.println("保存用户");
}
}
// CGLIB代理工厂
public class CglibProxyFactory implements MethodInterceptor {
private Object target;
public CglibProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置处理:" + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置处理:" + method.getName());
return result;
}
}
// 使用
UserService service = new UserService();
UserService proxy = (UserService) new CglibProxyFactory(service).getProxyInstance();
proxy.save();
代理模式对比:
| 特性 | 静态代理 | JDK动态代理 | CGLIB代理 |
|---|---|---|---|
| 实现方式 | 手动编写代理类 | 运行时生成代理类 | 运行时生成子类 |
| 目标要求 | 无特殊要求 | 必须实现接口 | 无要求(但不能是final类) |
| 性能 | 较好 | 较好 | 很好(但首次较慢) |
| 灵活性 | 低 | 高 | 高 |
应用场景:
- AOP实现:Spring AOP使用JDK动态代理和CGLIB
- 远程代理:RPC框架中的远程调用代理
- 虚拟代理:延迟加载,如Hibernate的懒加载
- 保护代理:权限控制
- 缓存代理:添加缓存功能
行为型模式
1. 策略模式(Strategy)
注意 :策略模式的完整实现示例请参考 01.03 Java基础篇|面向对象核心与设计实践 中的"常见设计模式深度解析"章节。
定义:定义一系列算法,把它们封装起来,并且使它们可以互换。
核心思想:
- 将算法封装成独立的策略类
- 通过组合的方式使用策略
- 可以在运行时切换策略
简单示例:
java
// 策略接口
public interface SortStrategy {
void sort(int[] array);
}
// 具体策略
public class BubbleSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
// 冒泡排序实现
System.out.println("使用冒泡排序");
}
}
public class QuickSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
// 快速排序实现
System.out.println("使用快速排序");
}
}
// 上下文类
public class SortContext {
private SortStrategy strategy;
public SortContext(SortStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(SortStrategy strategy) {
this.strategy = strategy;
}
public void executeSort(int[] array) {
strategy.sort(array);
}
}
// 使用
SortContext context = new SortContext(new BubbleSortStrategy());
context.executeSort(array);
context.setStrategy(new QuickSortStrategy());
context.executeSort(array);
应用场景:
- 算法可替换:需要多种算法,可以动态切换
- 消除if-else:用策略模式替代大量的if-else判断
- 支付方式选择:不同支付方式的处理逻辑
- 排序算法选择:根据数据特点选择不同排序算法
2. 观察者模式(Observer)
注意 :观察者模式的完整实现示例(包括JDK内置实现和Spring事件机制)请参考 01.03 Java基础篇|面向对象核心与设计实践 中的"常见设计模式深度解析"章节。
定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
核心角色:
- Subject(主题):被观察的对象
- Observer(观察者):观察主题的对象
- ConcreteSubject(具体主题):具体的被观察对象
- ConcreteObserver(具体观察者):具体的观察者
简单示例:
java
// 观察者接口
public interface Observer {
void update(String message);
}
// 主题接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
// 具体主题
public class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(news);
}
}
public void setNews(String news) {
this.news = news;
notifyObservers();
}
}
// 具体观察者
public class NewsChannel implements Observer {
private String name;
public NewsChannel(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " 收到新闻: " + message);
}
}
// 使用
NewsAgency agency = new NewsAgency();
agency.attach(new NewsChannel("CNN"));
agency.attach(new NewsChannel("BBC"));
agency.setNews("Breaking news!");
应用场景:
- 事件驱动系统:GUI事件处理
- 发布订阅模式:消息队列、事件总线
- Spring事件机制:ApplicationEvent和ApplicationListener
- MVC模式:Model变化时通知View更新
3. 模板方法模式(Template Method)
注意 :模板方法模式的完整实现示例请参考 01.03 Java基础篇|面向对象核心与设计实践 中的"常见设计模式深度解析"章节。
定义:定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
核心思想:
- 在抽象类中定义算法骨架(模板方法)
- 将可变步骤定义为抽象方法或钩子方法
- 子类实现具体的步骤
简单示例:
java
// 抽象模板类
public abstract class DataProcessor {
// 模板方法:定义算法骨架(final防止子类重写)
public final void process(String data) {
validate(data);
String processed = transform(data);
save(processed);
notifyCompletion();
}
// 钩子方法:子类可以重写
protected void validate(String data) {
if (data == null || data.isEmpty()) {
throw new IllegalArgumentException("Data cannot be empty");
}
}
// 抽象方法:子类必须实现
protected abstract String transform(String data);
// 默认实现:子类可以重写
protected void save(String data) {
System.out.println("Saving: " + data);
}
// 钩子方法
protected void notifyCompletion() {
System.out.println("Processing completed");
}
}
// 具体实现
public class XMLProcessor extends DataProcessor {
@Override
protected String transform(String data) {
return "<data>" + data + "</data>";
}
}
public class JSONProcessor extends DataProcessor {
@Override
protected String transform(String data) {
return "{\"data\": \"" + data + "\"}";
}
@Override
protected void save(String data) {
System.out.println("Saving JSON: " + data);
}
}
应用场景:
- 算法骨架固定:算法流程固定,但某些步骤可变
- 框架设计:Spring的AbstractApplicationContext.refresh()
- JdbcTemplate:Spring JDBC模板方法
- Servlet的doGet/doPost:HttpServlet的service()方法
4. 责任链模式(Chain of Responsibility)
定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
完整实现示例:
java
// 处理器抽象类
public abstract class Handler {
protected Handler nextHandler;
public void setNext(Handler handler) {
this.nextHandler = handler;
}
public abstract void handleRequest(Request request);
}
// 具体处理器
public class ManagerHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getAmount() <= 1000) {
System.out.println("经理审批通过: " + request.getAmount());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
public class DirectorHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getAmount() <= 5000) {
System.out.println("总监审批通过: " + request.getAmount());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
public class CEOHandler extends Handler {
@Override
public void handleRequest(Request request) {
System.out.println("CEO审批通过: " + request.getAmount());
}
}
// 请求类
public class Request {
private double amount;
public Request(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
// 使用
Handler manager = new ManagerHandler();
Handler director = new DirectorHandler();
Handler ceo = new CEOHandler();
manager.setNext(director);
director.setNext(ceo);
manager.handleRequest(new Request(8000));
应用场景:
- 审批流程:多级审批系统
- 过滤器链:Servlet Filter、Spring Interceptor
- 异常处理:异常处理链
- 日志处理:多级日志处理器
5. 命令模式(Command)
定义:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
完整实现示例:
java
// 命令接口
public interface Command {
void execute();
void undo();
}
// 具体命令
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
@Override
public void undo() {
light.turnOn();
}
}
// 接收者
public class Light {
public void turnOn() {
System.out.println("灯打开了");
}
public void turnOff() {
System.out.println("灯关闭了");
}
}
// 调用者
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// 使用
Light light = new Light();
Command lightOn = new LightOnCommand(light);
Command lightOff = new LightOffCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();
应用场景:
- 撤销/重做功能:文本编辑器、图形编辑器
- 宏命令:批量执行命令
- 队列请求:将请求放入队列,异步执行
- 日志记录:记录命令执行历史
6. 迭代器模式(Iterator)
定义:提供一种方法顺序访问一个聚合对象中各个元素,而又无须暴露该对象的内部表示。
Java中的迭代器模式:
java
// Java集合框架已经实现了迭代器模式
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// 使用迭代器遍历
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
// 增强for循环底层也是使用迭代器
for (String item : list) {
System.out.println(item);
}
自定义迭代器示例:
java
// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 聚合接口
public interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体聚合类
public class BookShelf implements Aggregate<Book> {
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
}
@Override
public Iterator<Book> createIterator() {
return new BookIterator(books);
}
}
// 具体迭代器
public class BookIterator implements Iterator<Book> {
private List<Book> books;
private int index = 0;
public BookIterator(List<Book> books) {
this.books = books;
}
@Override
public boolean hasNext() {
return index < books.size();
}
@Override
public Book next() {
return books.get(index++);
}
}
应用场景:
- 集合遍历:Java集合框架
- 树形结构遍历:文件系统、DOM树
- 数据库结果集遍历:ResultSet
7. 状态模式(State)
定义:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
完整实现示例:
java
// 状态接口
public interface State {
void handle(Context context);
}
// 具体状态
public class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态:A");
context.setState(new ConcreteStateB());
}
}
public class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态:B");
context.setState(new ConcreteStateA());
}
}
// 上下文类
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
// 使用
Context context = new Context(new ConcreteStateA());
context.request(); // 输出:当前状态:A
context.request(); // 输出:当前状态:B
应用场景:
- 状态机:订单状态(待支付、已支付、已发货等)
- 游戏角色状态:站立、行走、跑步
- 工作流引擎:流程状态转换
8. 备忘录模式(Memento)
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后恢复。
完整实现示例:
java
// 备忘录类
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 原发器类
public class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento saveStateToMemento() {
return new Memento(state);
}
public void getStateFromMemento(Memento memento) {
state = memento.getState();
}
}
// 管理者类
public class Caretaker {
private List<Memento> mementoList = new ArrayList<>();
public void add(Memento memento) {
mementoList.add(memento);
}
public Memento get(int index) {
return mementoList.get(index);
}
}
// 使用
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State #1");
caretaker.add(originator.saveStateToMemento());
originator.setState("State #2");
caretaker.add(originator.saveStateToMemento());
originator.getStateFromMemento(caretaker.get(0));
System.out.println(originator.getState()); // 输出:State #1
应用场景:
- 撤销/重做功能:文本编辑器、图形编辑器
- 游戏存档:保存游戏状态
- 数据库事务:回滚操作
9. 访问者模式(Visitor)
定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
完整实现示例:
java
// 元素接口
public interface Element {
void accept(Visitor visitor);
}
// 具体元素
public class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationA() {
return "ElementA";
}
}
public class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationB() {
return "ElementB";
}
}
// 访问者接口
public interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
// 具体访问者
public class ConcreteVisitor implements Visitor {
@Override
public void visit(ConcreteElementA element) {
System.out.println("访问 " + element.operationA());
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("访问 " + element.operationB());
}
}
// 对象结构
public class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void add(Element element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
应用场景:
- 编译器:AST(抽象语法树)的遍历
- 文件系统:对不同类型文件的处理
- XML解析:对不同节点的处理
高频面试问答(深度解析)
1. 单例模式实现?
标准答案:
- 双重检查锁定:线程安全,延迟加载
- 静态内部类:线程安全,延迟加载,推荐
- 枚举:线程安全,防止反射和序列化破坏
深入追问与回答思路:
Q: 双重检查锁定实现?
java
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Q: 为什么需要volatile?
- 防止指令重排序:new操作可能重排序
- 保证可见性:多线程环境下可见性
2. 工厂模式应用?
注意 :工厂模式的完整实现示例(包括简单工厂、工厂方法、抽象工厂)请参考 01.03 Java基础篇|面向对象核心与设计实践 章节。
标准答案:
- 简单工厂:一个工厂类创建所有产品
- 工厂方法:每个产品一个工厂类
- 抽象工厂:创建产品族
深入追问与回答思路:
Q: 三种工厂模式的区别?
| 特性 | 简单工厂 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 工厂数量 | 1个 | 多个(每个产品一个) | 多个(每个产品族一个) |
| 扩展性 | 需要修改工厂类 | 添加新工厂类 | 添加新工厂类 |
| 复杂度 | 简单 | 中等 | 复杂 |
| 适用场景 | 产品类型少 | 产品类型多 | 产品族多 |
Q: 简单工厂实现?
java
// 产品接口
public interface Product {
void use();
}
// 具体产品
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
public class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 简单工厂
public class SimpleFactory {
public static Product createProduct(String type) {
return switch (type) {
case "A" -> new ConcreteProductA();
case "B" -> new ConcreteProductB();
default -> throw new IllegalArgumentException("Unknown product type: " + type);
};
}
}
Q: 工厂方法实现?
java
// 产品接口
public interface Product {
void use();
}
// 具体产品
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 工厂接口
public interface Factory {
Product createProduct();
}
// 具体工厂
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
Q: 抽象工厂实现?
java
// 产品族接口
public interface Button {
void render();
}
public interface Checkbox {
void render();
}
// Windows产品族
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("Windows Button");
}
}
public class WindowsCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("Windows Checkbox");
}
}
// Mac产品族
public class MacButton implements Button {
@Override
public void render() {
System.out.println("Mac Button");
}
}
public class MacCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("Mac Checkbox");
}
}
// 抽象工厂
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 具体工厂
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
3. 代理模式实现?
标准答案:
- 静态代理:代理类手动编写
- JDK动态代理:基于接口,使用Proxy类
- CGLIB代理:基于继承,使用字节码技术
深入追问与回答思路:
Q: JDK动态代理实现?
java
// 接口
public interface UserService {
void save();
}
// 实现类
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户");
}
}
// 代理类
public class ProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
}
);
}
}
设计模式对比与选择
创建型模式对比
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 单例 | 全局唯一实例 | 节省资源,控制访问 | 难以测试,违反单一职责 |
| 工厂 | 对象创建复杂 | 解耦创建和使用 | 增加类数量 |
| 建造者 | 参数多且可选 | 灵活,可读性好 | 代码量大 |
结构型模式对比
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 适配器 | 接口不兼容 | 复用现有类 | 增加复杂度 |
| 装饰器 | 动态扩展功能 | 灵活,避免类爆炸 | 多层装饰时复杂 |
| 代理 | 控制访问 | 职责清晰 | 增加间接层 |
行为型模式对比
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 策略 | 算法可替换 | 消除if-else | 客户端需了解策略 |
| 观察者 | 一对多依赖 | 松耦合 | 通知顺序不确定 |
| 模板方法 | 算法骨架固定 | 代码复用 | 继承关系固定 |
设计模式在框架中的应用
Spring框架中的设计模式
- 单例模式:Spring Bean默认单例
- 工厂模式:BeanFactory、ApplicationContext
- 代理模式:AOP实现(JDK动态代理、CGLIB)
- 模板方法模式:JdbcTemplate、RestTemplate
- 观察者模式:ApplicationEvent和ApplicationListener
- 策略模式:Resource接口的不同实现
- 适配器模式:HandlerAdapter
MyBatis中的设计模式
- 建造者模式:SqlSessionFactoryBuilder
- 工厂模式:SqlSessionFactory
- 代理模式:Mapper接口代理
- 模板方法模式:BaseExecutor
设计模式最佳实践
1. 不要过度设计
- 简单问题用简单方案
- 不要为了使用模式而使用模式
- 优先考虑代码可读性和可维护性
2. 理解模式本质
- 理解模式解决的问题
- 理解模式的适用场景
- 不要死记硬背,要灵活运用
3. 组合使用模式
- 实际项目中往往组合使用多个模式
- 如:工厂模式 + 策略模式、观察者模式 + 模板方法模式
4. 重构到模式
- 先写代码,发现痛点后再重构
- 不要一开始就设计复杂的模式
- 通过重构逐步引入模式
延伸阅读
- 《设计模式:可复用面向对象软件的基础》(GoF经典著作)
- 《Head First设计模式》(通俗易懂,适合入门)
- 《重构:改善既有代码的设计》(Martin Fowler)
- Spring源码中的设计模式应用
- Java设计模式实战案例