1. 设计模式概述:为什么每个Java开发者都需要掌握
2004年我第一次接手一个遗留系统时,面对满屏的if-else和重复代码,第一次深刻体会到设计模式的价值。设计模式不是象牙塔里的理论,而是解决特定场景下代码组织问题的经典方案。在Java生态中,从JDK到主流框架,设计模式无处不在——ArrayList用了迭代器模式,Spring依赖注入基于工厂模式,MyBatis的Executor采用模板方法模式。
掌握设计模式能让你:
- 写出更易维护的扩展性代码(开闭原则)
- 提升代码复用率(组合优于继承)
- 让团队协作更高效(模式即沟通语言)
- 快速理解框架源码(比如Spring的BeanFactory)
注意:不要为了用模式而用模式。我曾见过把简单查询强行套用策略模式的反例,反而增加了复杂度。模式是手段不是目的。
2. 创建型模式:对象诞生的艺术
2.1 单例模式的线程安全实践
双检锁实现是面试常考点,但Java 5之后更推荐枚举实现:
java复制public enum Singleton {
INSTANCE;
public void businessMethod() {
// 业务逻辑
}
}
这种写法天然防反射攻击和序列化破坏,Joshua Bloch在《Effective Java》中力荐。
2.2 工厂方法 vs 抽象工厂
通过一个数据库连接示例对比:
java复制// 工厂方法
interface ConnectionFactory {
Connection createConnection();
}
// 抽象工厂
interface DatabaseFactory {
Connection createConnection();
Statement createStatement();
}
Spring的BeanFactory是抽象工厂的典型应用,而MyBatis的SqlSessionFactory则是工厂方法。
2.3 建造者模式在复杂对象构造中的应用
当构造参数超过4个时,建造者模式能显著提升可读性。Lombok的@Builder注解可以自动生成建造者代码:
java复制@Builder
public class HttpClientConfig {
private int connectTimeout;
private int readTimeout;
private boolean gzipEnabled;
// 其他10+配置项...
}
// 使用方式
HttpClientConfig config = HttpClientConfig.builder()
.connectTimeout(5000)
.readTimeout(10000)
.build();
3. 结构型模式:构建灵活架构
3.1 适配器模式解决接口不兼容问题
实际开发中常见的三种适配场景:
- 类适配器(继承实现)
- 对象适配器(组合实现)
- 接口默认方法(Java 8+)
java复制// 老系统接口
interface LegacyLogger {
void log(String message);
}
// 新系统接口
interface ModernLogger {
void debug(String msg);
void info(String msg);
}
// 适配器实现
class LoggerAdapter implements ModernLogger {
private LegacyLogger legacyLogger;
@Override
public void debug(String msg) {
legacyLogger.log("DEBUG: " + msg);
}
}
3.2 装饰器模式实现动态扩展
Java I/O流是经典案例:
java复制// 基础组件
InputStream input = new FileInputStream("data.txt");
// 装饰器叠加
InputStream buffered = new BufferedInputStream(input);
InputStream gzip = new GZIPInputStream(buffered);
与代理模式的区别在于:装饰器侧重功能增强,代理侧重访问控制。
3.3 组合模式处理树形结构
组织架构管理示例:
java复制interface OrganizationComponent {
void display();
}
class Department implements OrganizationComponent {
private List<OrganizationComponent> children = new ArrayList<>();
public void add(OrganizationComponent comp) {
children.add(comp);
}
@Override
public void display() {
children.forEach(OrganizationComponent::display);
}
}
4. 行为型模式:对象间的协作之道
4.1 观察者模式的现代化实现
Java自带Observable类已过时,推荐使用PropertyChangeListener或RxJava:
java复制// 使用PropertyChangeSupport
public class WeatherStation {
private PropertyChangeSupport support = new PropertyChangeSupport(this);
public void addListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
private void temperatureChanged(int newTemp) {
support.firePropertyChange("temperature",
this.currentTemp, newTemp);
}
}
4.2 策略模式消除条件语句
支付方式选择案例:
java复制interface PaymentStrategy {
void pay(BigDecimal amount);
}
class PaymentContext {
private PaymentStrategy strategy;
public void executePayment(BigDecimal amount) {
strategy.pay(amount);
}
}
// 使用Lambda简化实现
PaymentContext alipayContext = new PaymentContext();
alipayContext.setStrategy(amount -> System.out.println("支付宝支付:" + amount));
4.3 模板方法模式封装算法骨架
JdbcTemplate的简化版实现:
java复制public abstract class JdbcTemplate {
public final Object execute(String sql) {
Connection conn = null;
try {
conn = getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
// 交给子类实现
setParameters(ps);
ResultSet rs = ps.executeQuery();
// 交给子类实现
return mapResult(rs);
} finally {
closeConnection(conn);
}
}
protected abstract void setParameters(PreparedStatement ps);
protected abstract Object mapResult(ResultSet rs);
}
5. 模式混用实战案例
5.1 Spring框架中的模式组合
- 单例+工厂:BeanFactory
- 代理+模板方法:TransactionTemplate
- 观察者+适配器:ApplicationEvent机制
5.2 电商优惠系统设计
java复制// 策略模式计算优惠
interface DiscountStrategy {
BigDecimal apply(BigDecimal original);
}
// 装饰器模式叠加优惠
class CouponDecorator implements DiscountStrategy {
private DiscountStrategy wrapped;
private BigDecimal couponAmount;
@Override
public BigDecimal apply(BigDecimal original) {
return wrapped.apply(original).subtract(couponAmount);
}
}
// 工厂方法创建策略
class StrategyFactory {
public static DiscountStrategy create(String userType) {
switch(userType) {
case "VIP": return new VipDiscount();
case "NEW": return new NewUserDiscount();
default: return new RegularDiscount();
}
}
}
6. 设计模式演进与Java新特性
6.1 Lambda表达式对模式的简化
命令模式传统实现:
java复制interface Command {
void execute();
}
class Button {
private Command command;
public void onClick() {
command.execute();
}
}
Lambda版本:
java复制Button button = new Button();
button.setOnClick(() -> System.out.println("Clicked"));
6.2 模块化对单例的挑战
Java 9模块系统要求显式导出包,这可能导致反射创建单例失败。解决方案:
java复制module my.module {
exports com.example to
spring.core, hibernate, etc;
}
6.3 记录类(Record)与不变性模式
Java 14引入的Record简化了不可变对象的创建:
java复制public record Point(int x, int y) {}
// 等效于:
public final class Point {
private final int x;
private final int y;
// 自动生成构造器/equals/hashCode/toString
}
7. 反模式与过度设计警示
我在代码审查中常见的反模式:
- 滥用单例导致测试困难
- 过度使用抽象工厂增加复杂度
- 装饰器嵌套过深影响性能
一个经验法则:当发现自己在强行套用模式时,很可能已经过度设计。我曾重构过一个用了7层装饰器的文件处理器,简化为组合模式后性能提升40%。
设计模式的选用应该遵循:
- 先写出可工作的简单代码
- 识别出真正的痛点
- 选择最轻量的模式解决问题
- 持续重构优化
记住:没有"最好的"设计模式,只有最适合当前场景的解决方案。就像Gof在《设计模式》开篇强调的——这些模式是描述而非规定。