设计模式是软件开发的最佳实践,掌握设计模式是成为架构师的必经之路。本文将深入剖析常用设计模式的原理和应用场景,助你写出优雅、可维护的代码。
一、设计模式概述
1.1 什么是设计模式?
关键点: 设计模式是在软件开发中反复出现的问题的通用解决方案。
设计模式的六大原则:
- 单一职责原则(SRP):一个类只负责一个功能
- 开闭原则(OCP):对扩展开放,对修改关闭
3.里氏替换原则(LSP):子类可以替换父类 - 依赖倒置原则(DIP):依赖抽象而非具体
- 接口隔离原则(ISP):接口应该小而专
- 迪米特法则(LOD):最少知识原则
23种设计模式分类:
- 创建型模式(5种):单例、工厂、抽象工厂、建造者、原型
- 结构型模式(7种):适配器、桥接、组合、装饰器、外观、享元、代理
- 行为型模式(11种):责任链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法、访问者
二、创建型模式
2.1 单例模式(Singleton)
关键点: 确保一个类只有一个实例,并提供全局访问点。
java
// ❌ 懒汉式(线程不安全)
public class Singleton1 {
private static Singleton1 instance;
private Singleton1() {}
public static Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1(); // 多线程问题
}
return instance;
}
}
// ✅ 饿汉式(线程安全,推荐)
public class Singleton2 {
private static final Singleton2 INSTANCE = new Singleton2();
private Singleton2() {}
public static Singleton2 getInstance() {
return INSTANCE;
}
}
// ✅ 双重检查锁(DCL,推荐)
public class Singleton3 {
private static volatile Singleton3 instance;
private Singleton3() {}
public static Singleton3 getInstance() {
if (instance == null) {
synchronized (Singleton3.class) {
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
// ✅ 静态内部类(推荐)
public class Singleton4 {
private Singleton4() {}
private static class Holder {
private static final Singleton4 INSTANCE = new Singleton4();
}
public static Singleton4 getInstance() {
return Holder.INSTANCE;
}
}
// ✅ 枚举(最安全,推荐)
public enum Singleton5 {
INSTANCE;
public void doSomething() {
System.out.println("单例方法");
}
}
应用场景:
- 数据库连接池
- 配置管理器
- 日志对象
- 线程池
2.2 工厂模式(Factory)
关键点: 定义创建对象的接口,让子类决定实例化哪个类。
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 Client1 {
public static void main(String[] args) {
Product product = new ConcreteProductA(); // 直接依赖具体类
product.use();
}
}
// ✅ 简单工厂模式
public class SimpleFactory {
public static Product createProduct(String type) {
switch (type) {
case "A":
return new ConcreteProductA();
case "B":
return new ConcreteProductB();
default:
throw new IllegalArgumentException("未知产品类型");
}
}
}
// 使用
public class Client2 {
public static void main(String[] args) {
Product product = SimpleFactory.createProduct("A");
product.use();
}
}
// ✅ 工厂方法模式
public interface Factory {
Product createProduct();
}
public class FactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class FactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 使用
public class Client3 {
public static void main(String[] args) {
Factory factory = new FactoryA();
Product product = factory.createProduct();
product.use();
}
}
应用场景:
- JDBC连接
- Spring的BeanFactory
- 日志框架(SLF4J)
2.3 建造者模式(Builder)
关键点: 将复杂对象的构建与表示分离,使同样的构建过程可以创建不同的表示。
java
// ❌ 传统构造方法(参数过多)
public class Computer1 {
private String cpu;
private String ram;
private String disk;
private String gpu;
private String monitor;
public Computer1(String cpu, String ram, String disk,
String gpu, String monitor) {
this.cpu = cpu;
this.ram = ram;
this.disk = disk;
this.gpu = gpu;
this.monitor = monitor;
}
}
// 使用:参数顺序容易搞错
Computer1 computer = new Computer1("i7", "16G", "512G", "RTX3060", "27寸");
// ✅ 建造者模式
public class Computer {
private String cpu;
private String ram;
private String disk;
private String gpu;
private String monitor;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.disk = builder.disk;
this.gpu = builder.gpu;
this.monitor = builder.monitor;
}
public static class Builder {
private String cpu;
private String ram;
private String disk;
private String gpu;
private String monitor;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder ram(String ram) {
this.ram = ram;
return this;
}
public Builder disk(String disk) {
this.disk = disk;
return this;
}
public Builder gpu(String gpu) {
this.gpu = gpu;
return this;
}
public Builder monitor(String monitor) {
this.monitor = monitor;
return this;
}
public Computer build() {
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", disk='" + disk + '\'' +
", gpu='" + gpu + '\'' +
", monitor='" + monitor + '\'' +
'}';
}
}
// 使用:链式调用,清晰易读
Computer computer = new Computer.Builder()
.cpu("i7")
.ram("16G")
.disk("512G")
.gpu("RTX3060")
.monitor("27寸")
.build();
应用场景:
- StringBuilder
- Lombok的@Builder
- OkHttp的Request构建
三、结构型模式
3.1 代理模式(Proxy)
关键点: 为其他对象提供一种代理以控制对这个对象的访问。
java
// 接口
public interface UserService {
void save(String user);
String query(String id);
}
// 真实对象
public class UserServiceImpl implements UserService {
@Override
public void save(String user) {
System.out.println("保存用户:" + user);
}
@Override
public String query(String id) {
System.out.println("查询用户:" + id);
return "User-" + id;
}
}
// ✅ 静态代理
public class UserServiceProxy implements UserService {
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void save(String user) {
System.out.println("开始事务");
target.save(user);
System.out.println("提交事务");
}
@Override
public String query(String id) {
System.out.println("权限检查");
String result = target.query(id);
System.out.println("日志记录");
return result;
}
}
// ✅ 动态代理(JDK)
public class JdkProxyFactory {
public static <T> T createProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("方法执行前:" + method.getName());
Object result = method.invoke(target, args);
System.out.println("方法执行后");
return result;
}
);
}
}
// 使用
public class ProxyDemo {
public static void main(String[] args) {
// 静态代理
UserService proxy1 = new UserServiceProxy(new UserServiceImpl());
proxy1.save("张三");
// 动态代理
UserService proxy2 = JdkProxyFactory.createProxy(new UserServiceImpl());
proxy2.query("123");
}
}
应用场景:
- Spring AOP
- MyBatis的Mapper接口
- RPC远程调用
3.2 装饰器模式(Decorator)
关键点: 动态地给对象添加额外的职责,比继承更灵活。
java
// 组件接口
public interface Coffee {
double cost();
String description();
}
// 具体组件
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 10.0;
}
@Override
public String description() {
return "普通咖啡";
}
}
// 装饰器基类
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
// 具体装饰器:加奶
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 2.0;
}
@Override
public String description() {
return coffee.description() + " + 牛奶";
}
}
// 具体装饰器:加糖
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 1.0;
}
@Override
public String description() {
return coffee.description() + " + 糖";
}
}
// 使用
public class DecoratorDemo {
public static void main(String[] args) {
// 普通咖啡
Coffee coffee1 = new SimpleCoffee();
System.out.println(coffee1.description() + " = " + coffee1.cost());
// 加奶咖啡
Coffee coffee2 = new MilkDecorator(new SimpleCoffee());
System.out.println(coffee2.description() + " = " + coffee2.cost());
// 加奶加糖咖啡
Coffee coffee3 = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
System.out.println(coffee3.description() + " = " + coffee3.cost());
}
}
应用场景:
- Java I/O流(BufferedReader、InputStreamReader)
- Spring的BeanWrapper
- MyBatis的Cache
四、行为型模式
4.1 策略模式(Strategy)
关键点: 定义一系列算法,把它们封装起来,并且使它们可以互相替换。
java
// ❌ 不使用策略模式
public class PaymentService1 {
public void pay(String type, double amount) {
if ("alipay".equals(type)) {
System.out.println("支付宝支付:" + amount);
} else if ("wechat".equals(type)) {
System.out.println("微信支付:" + amount);
} else if ("bank".equals(type)) {
System.out.println("银行卡支付:" + amount);
}
// 新增支付方式需要修改代码,违反开闭原则
}
}
// ✅ 策略模式
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount);
}
}
public class WechatStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount);
}
}
public class BankCardStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("银行卡支付:" + amount);
}
}
// 上下文
public class PaymentContext {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void pay(double amount) {
strategy.pay(amount);
}
}
// 使用
public class StrategyDemo {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();
// 使用支付宝
context.setStrategy(new AlipayStrategy());
context.pay(100);
// 切换为微信支付
context.setStrategy(new WechatStrategy());
context.pay(200);
}
}
应用场景:
- 支付方式选择
- 排序算法选择
- 文件压缩算法
4.2 观察者模式(Observer)
关键点: 定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知。
java
// 观察者接口
public interface Observer {
void update(String message);
}
// 具体观察者
public class EmailObserver implements Observer {
private String email;
public EmailObserver(String email) {
this.email = email;
}
@Override
public void update(String message) {
System.out.println("发送邮件到 " + email + ": " + message);
}
}
public class SmsObserver implements Observer {
private String phone;
public SmsObserver(String phone) {
this.phone = phone;
}
@Override
public void update(String message) {
System.out.println("发送短信到 " + phone + ": " + message);
}
}
// 主题(被观察者)
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
// 使用
public class ObserverDemo {
public static void main(String[] args) {
Subject subject = new Subject();
// 注册观察者
subject.attach(new EmailObserver("user@example.com"));
subject.attach(new SmsObserver("13800138000"));
// 通知所有观察者
subject.notifyObservers("订单已发货");
}
}
应用场景:
- 事件监听机制
- MVC模式中的Model-View关系
- 消息队列
4.3 模板方法模式(Template Method)
关键点: 定义算法骨架,将某些步骤延迟到子类实现。
java
// 抽象类
public abstract class DataProcessor {
// 模板方法(final防止子类重写)
public final void process() {
readData();
processData();
writeData();
}
// 具体方法
private void readData() {
System.out.println("读取数据");
}
// 抽象方法(子类必须实现)
protected abstract void processData();
// 钩子方法(子类可选择性重写)
protected void writeData() {
System.out.println("写入数据");
}
}
// 具体类
public class CsvDataProcessor extends DataProcessor {
@Override
protected void processData() {
System.out.println("处理CSV数据");
}
}
public class JsonDataProcessor extends DataProcessor {
@Override
protected void processData() {
System.out.println("处理JSON数据");
}
@Override
protected void writeData() {
System.out.println("写入JSON文件");
}
}
// 使用
public class TemplateDemo {
public static void main(String[] args) {
DataProcessor csv = new CsvDataProcessor();
csv.process();
System.out.println("---");
DataProcessor json = new JsonDataProcessor();
json.process();
}
}
应用场景:
- Spring的JdbcTemplate
- Servlet的service方法
- 测试框架的setUp/tearDown
五、实战案例:电商订单系统
java
// 1. 单例模式:配置管理器
public class ConfigManager {
private static volatile ConfigManager instance;
private Properties properties;
private ConfigManager() {
properties = new Properties();
// 加载配置文件
}
public static ConfigManager getInstance() {
if (instance == null) {
synchronized (ConfigManager.class) {
if (instance == null) {
instance = new ConfigManager();
}
}
}
return instance;
}
public String getProperty(String key) {
return properties.getProperty(key);
}
}
// 2. 工厂模式:订单创建
public interface Order {
void create();
void pay();
}
public class NormalOrder implements Order {
@Override
public void create() {
System.out.println("创建普通订单");
}
@Override
public void pay() {
System.out.println("普通订单支付");
}
}
public class GroupOrder implements Order {
@Override
public void create() {
System.out.println("创建团购订单");
}
@Override
public void pay() {
System.out.println("团购订单支付");
}
}
public class OrderFactory {
public static Order createOrder(String type) {
switch (type) {
case "normal":
return new NormalOrder();
case "group":
return new GroupOrder();
default:
throw new IllegalArgumentException("未知订单类型");
}
}
}
// 3. 策略模式:优惠计算
public interface DiscountStrategy {
double calculate(double amount);
}
public class NoDiscountStrategy implements DiscountStrategy {
@Override
public double calculate(double amount) {
return amount;
}
}
public class PercentDiscountStrategy implements DiscountStrategy {
private double percent;
public PercentDiscountStrategy(double percent) {
this.percent = percent;
}
@Override
public double calculate(double amount) {
return amount * percent;
}
}
public class FullReductionStrategy implements DiscountStrategy {
private double full;
private double reduction;
public FullReductionStrategy(double full, double reduction) {
this.full = full;
this.reduction = reduction;
}
@Override
public double calculate(double amount) {
return amount >= full ? amount - reduction : amount;
}
}
// 4. 观察者模式:订单状态通知
public interface OrderObserver {
void onOrderStatusChanged(String orderId, String status);
}
public class EmailNotifier implements OrderObserver {
@Override
public void onOrderStatusChanged(String orderId, String status) {
System.out.println("邮件通知:订单" + orderId + "状态变更为" + status);
}
}
public class SmsNotifier implements OrderObserver {
@Override
public void onOrderStatusChanged(String orderId, String status) {
System.out.println("短信通知:订单" + orderId + "状态变更为" + status);
}
}
public class OrderSubject {
private List<OrderObserver> observers = new ArrayList<>();
public void addObserver(OrderObserver observer) {
observers.add(observer);
}
public void changeStatus(String orderId, String status) {
System.out.println("订单" + orderId + "状态变更为:" + status);
notifyObservers(orderId, status);
}
private void notifyObservers(String orderId, String status) {
for (OrderObserver observer : observers) {
observer.onOrderStatusChanged(orderId, status);
}
}
}
// 5. 建造者模式:订单构建
public class OrderInfo {
private String orderId;
private String userId;
private List<String> products;
private double amount;
private String address;
private String remark;
private OrderInfo(Builder builder) {
this.orderId = builder.orderId;
this.userId = builder.userId;
this.products = builder.products;
this.amount = builder.amount;
this.address = builder.address;
this.remark = builder.remark;
}
public static class Builder {
private String orderId;
private String userId;
private List<String> products = new ArrayList<>();
private double amount;
private String address;
private String remark;
public Builder orderId(String orderId) {
this.orderId = orderId;
return this;
}
public Builder userId(String userId) {
this.userId = userId;
return this;
}
public Builder addProduct(String product) {
this.products.add(product);
return this;
}
public Builder amount(double amount) {
this.amount = amount;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder remark(String remark) {
this.remark = remark;
return this;
}
public OrderInfo build() {
return new OrderInfo(this);
}
}
@Override
public String toString() {
return "OrderInfo{" +
"orderId='" + orderId + '\'' +
", userId='" + userId + '\'' +
", products=" + products +
", amount=" + amount +
", address='" + address + '\'' +
", remark='" + remark + '\'' +
'}';
}
}
// 综合使用
public class ECommerceDemo {
public static void main(String[] args) {
// 1. 创建订单
Order order = OrderFactory.createOrder("normal");
order.create();
// 2. 构建订单信息
OrderInfo orderInfo = new OrderInfo.Builder()
.orderId("ORDER001")
.userId("USER001")
.addProduct("商品A")
.addProduct("商品B")
.amount(299.0)
.address("北京市朝阳区")
.remark("尽快发货")
.build();
System.out.println(orderInfo);
// 3. 计算优惠
DiscountStrategy strategy = new FullReductionStrategy(200, 30);
double finalAmount = strategy.calculate(orderInfo.amount);
System.out.println("优惠后金额:" + finalAmount);
// 4. 订单状态通知
OrderSubject subject = new OrderSubject();
subject.addObserver(new EmailNotifier());
subject.addObserver(new SmsNotifier());
subject.changeStatus("ORDER001", "已支付");
subject.changeStatus("ORDER001", "已发货");
}
}
六、设计模式对比
6.1 工厂模式 vs 建造者模式
| 特性 | 工厂模式 | 建造者模式 |
|---|---|---|
| 目的 | 创建对象 | 构建复杂对象 |
| 关注点 | 创建什么 | 如何创建 |
| 参数 | 简单参数 | 复杂参数 |
| 使用场景 | 创建简单对象 | 创建复杂对象 |
6.2 代理模式 vs 装饰器模式
| 特性 | 代理模式 | 装饰器模式 |
|---|---|---|
| 目的 | 控制访问 | 增强功能 |
| 关注点 | 访问控制 | 功能扩展 |
| 对象关系 | 代理持有真实对象 | 装饰器包装组件 |
| 使用场景 | 权限控制、延迟加载 | 动态添加功能 |
6.3 策略模式 vs 状态模式
| 特性 | 策略模式 | 状态模式 |
|---|---|---|
| 目的 | 算法替换 | 状态转换 |
| 关注点 | 行为选择 | 状态变化 |
| 切换方式 | 客户端切换 | 自动切换 |
| 使用场景 | 多种算法选择 | 对象状态变化 |
七、常见面试题
7.1 单例模式的几种实现方式?
- 饿汉式:类加载时创建,线程安全
- 懒汉式:使用时创建,需要同步
- 双重检查锁:延迟加载+线程安全
- 静态内部类:延迟加载+线程安全
- 枚举:最安全,防止反射和序列化破坏
7.2 Spring中使用了哪些设计模式?
- 单例模式:Bean默认单例
- 工厂模式:BeanFactory
- 代理模式:AOP
- 模板方法:JdbcTemplate
- 观察者模式:事件监听
- 适配器模式:HandlerAdapter
- 装饰器模式:BeanWrapper
7.3 如何选择合适的设计模式?
- 分析问题本质
- 考虑扩展性和维护性
- 遵循设计原则
- 不要过度设计
- 结合实际场景
八、总结
设计模式的核心要点:
- 创建型 - 如何创建对象
- 结构型 - 如何组合对象
- 行为型 - 对象间如何协作
最佳实践:
- 理解设计原则,灵活运用模式
- 不要为了用模式而用模式
- 结合实际业务场景选择
- 保持代码简洁,避免过度设计
学习建议:
- 先理解原理,再看源码
- 多写代码,多实践
- 阅读优秀框架源码
- 总结归纳,形成自己的理解
相关资源
- 《设计模式:可复用面向对象软件的基础》
- 《Head First设计模式》
- 设计模式在线学习
💡 小贴士: 设计模式不是银弹,要根据实际情况灵活运用!
关注我,获取更多Java干货! ☕