1. 设计模式入门:为什么每个Java开发者都需要掌握
刚入行那会儿,我总觉得设计模式是那些架构师才需要懂的高级玩意儿。直到有次接手一个老项目,看到满屏的if-else和重复代码,才明白为什么前辈总说"不懂设计模式,写再多代码也是初级工"。设计模式就像是编程中的成语,用好了能让代码更优雅、更易维护。
举个真实案例:去年我们电商系统要做优惠活动,最初版本用了大量条件判断来处理不同类型的优惠券。结果每次新增优惠类型都要修改核心逻辑,测试用例越写越多。后来用策略模式重构后,新优惠类型只需新增一个策略类,核心代码完全不用动。这就是设计模式的威力——它不是炫技,而是解决实际问题的工具箱。
2. 设计模式核心分类与适用场景
2.1 创建型模式:对象的诞生艺术
工厂方法模式是我最推荐新手优先掌握的。记得第一次用工厂方法是在支付模块开发时,需要根据支付类型(支付宝、微信、银联)创建不同的支付处理器。原始写法是这样的:
java复制if("alipay".equals(type)){
processor = new AlipayProcessor();
} else if("wechat".equals(type)){
processor = new WechatProcessor();
}
// 更多if-else...
用工厂方法改造后:
java复制public interface PaymentFactory {
PaymentProcessor createProcessor();
}
public class AlipayFactory implements PaymentFactory {
@Override
public PaymentProcessor createProcessor() {
return new AlipayProcessor();
}
}
// 使用时
PaymentFactory factory = FactoryCreator.getFactory(type);
PaymentProcessor processor = factory.createProcessor();
关键技巧:工厂类通常设计为单例,可以考虑用枚举实现,既线程安全又防反射攻击
2.2 结构型模式:构建代码大厦的钢筋
适配器模式在对接第三方库时特别有用。最近我们系统要接入新的短信服务商,但他们的SDK接口与我们现有系统不兼容。这时候不需要重写业务逻辑,只需做个适配器:
java复制public class NewSmsAdapter implements OurSmsService {
private final ThirdPartySmsLib thirdPartyLib;
public NewSmsAdapter(ThirdPartySmsLib lib) {
this.thirdPartyLib = lib;
}
@Override
public void send(String phone, String content) {
thirdPartyLib.sendSms(
new SmsRequest(phone, content, "default-template")
);
}
}
这样业务代码完全不用修改,只需在初始化时注入适配器实例。这种"用新瓶装旧酒"的思路,在系统演进过程中特别实用。
2.3 行为型模式:对象间的沟通之道
观察者模式在事件驱动系统中必不可少。比如用户注册成功后要执行多种操作(发欢迎邮件、初始化账户、送优惠券等),用观察者模式可以这样实现:
java复制public class UserRegisterEventPublisher {
private final List<UserRegisterListener> listeners = new ArrayList<>();
public void addListener(UserRegisterListener listener) {
listeners.add(listener);
}
public void publishEvent(User user) {
for(UserRegisterListener listener : listeners) {
listener.onUserRegistered(user);
}
}
}
// 使用示例
publisher.addListener(new WelcomeEmailSender());
publisher.addListener(new AccountInitializer());
publisher.publishEvent(newUser);
实际项目中建议用Guava的EventBus或Spring事件机制,但理解原生实现原理很重要
3. 模式实战:从理论到落地的关键步骤
3.1 识别模式适用场景的四大信号
-
变化点分析:当发现某处代码经常因同类原因修改时。比如我们物流系统最初用if-else计算运费,后来不同地区政策频繁调整,改用策略模式后维护成本降低70%
-
重复代码检测:相似的代码结构出现在多个地方。比如多个DAO都有相似的缓存逻辑,可以用模板方法模式抽象
-
复杂条件判断:方法中有大量switch-case或if-else分支。状态模式可以优雅地解决这种问题
-
类间关系混乱:对象之间直接调用形成网状结构。中介者模式能解耦这种紧耦合
3.2 模式实现的五个实操要点
-
接口先行:先定义抽象接口再实现具体类。比如策略模式要先定义策略接口
-
组合优于继承:多用has-a少用is-a。装饰器模式就是典型例子
-
开闭原则:对扩展开放,对修改关闭。用工厂方法新增产品类型时无需修改已有代码
-
单一职责:每个类/方法只做一件事。比如观察者模式将事件产生和处理分离
-
依赖倒置:依赖抽象而非具体实现。这是所有模式的基础
3.3 代码重构实战:用模式优化烂代码
来看个真实案例,这是某订单状态处理的原始代码:
java复制public void handleOrderStatus(Order order, String status) {
if("PAID".equals(status)) {
// 20行处理逻辑
inventoryService.reduceStock(order);
paymentService.confirm(order);
// ...
} else if("SHIPPED".equals(status)) {
// 15行处理逻辑
logisticsService.createWaybill(order);
notificationService.sendSms(order.getUser());
// ...
}
// 更多else-if...
}
用状态模式重构后:
java复制public interface OrderState {
void handle(OrderContext context);
}
public class PaidState implements OrderState {
@Override
public void handle(OrderContext context) {
inventoryService.reduceStock(context.getOrder());
paymentService.confirm(context.getOrder());
context.setState(new ShippedState());
}
}
// 使用方式
OrderState state = StateFactory.getState(status);
state.handle(orderContext);
重构后每新增一个状态只需添加新状态类,核心处理器完全不用修改,符合开闭原则。
4. 避坑指南:设计模式常见误用与修正
4.1 过度设计的五种症状
-
模式嵌套模式:在简单场景下使用多个模式组合,比如工厂里套策略再套装饰器
-
为模式而模式:没有实际需求强行使用模式,比如10个if-else就硬要改成策略模式
-
抽象过度:过早创建大量抽象层,导致系统复杂度陡增
-
性能牺牲:某些模式会增加对象创建开销(如装饰器模式),在性能敏感场景要谨慎
-
模式混用:同一个问题域混用多种解决思路,比如既用观察者又用责任链处理事件
4.2 新手最常踩的三大坑
坑1:单例的线程安全问题
错误示范:
java复制public class UnsafeSingleton {
private static UnsafeSingleton instance;
public static UnsafeSingleton getInstance() {
if(instance == null) {
instance = new UnsafeSingleton();
}
return instance;
}
}
正确写法(枚举式单例):
java复制public enum SafeSingleton {
INSTANCE;
public void doSomething() {
// ...
}
}
坑2:过度使用继承
错误示范:
java复制class Report {}
class PDFReport extends Report {}
class ExcelReport extends Report {}
// 新增导出类型就要新增子类
更好的做法(组合+策略):
java复制interface ExportStrategy {
void export(Report report);
}
class PDFExport implements ExportStrategy { /*...*/ }
class ExcelExport implements ExportStrategy { /*...*/ }
class ReportExporter {
private ExportStrategy strategy;
public ReportExporter(ExportStrategy strategy) {
this.strategy = strategy;
}
public void export(Report report) {
strategy.export(report);
}
}
坑3:滥用观察者导致内存泄漏
常见于Android开发:
java复制// Activity中
eventBus.register(this); // 注册监听
// 但忘记在onDestroy中取消注册
// 正确做法
@Override
protected void onDestroy() {
eventBus.unregister(this);
super.onDestroy();
}
4.3 模式选择决策树
遇到设计问题时可以这样思考:
- 是创建对象的问题吗?→ 考虑工厂、建造者、原型
- 是接口不兼容?→ 适配器
- 需要动态添加功能?→ 装饰器
- 算法/策略需要切换?→ 策略
- 对象状态变化影响行为?→ 状态
- 一对多的依赖关系?→ 观察者
5. 模式进阶:从应用到原理的深度理解
5.1 JDK中的模式实现赏析
- 迭代器模式:Java集合框架的
Iterator
java复制List<String> list = Arrays.asList("a", "b", "c");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
- 装饰器模式:IO流体系
java复制// 最经典的装饰器案例
InputStream is = new BufferedInputStream(
new FileInputStream("test.txt"));
- 代理模式:动态代理
java复制public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("Before method");
Object result = method.invoke(target, args);
System.out.println("After method");
return result;
});
}
5.2 Spring框架中的模式运用
- 模板方法:
JdbcTemplate等XXXTemplate类
java复制jdbcTemplate.execute("SELECT * FROM users", (ResultSet rs) -> {
// 处理结果集
return null;
});
- 工厂模式:
BeanFactory体系
java复制ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
MyService service = context.getBean(MyService.class);
- 代理模式:AOP实现
java复制@Aspect
@Component
public class LogAspect {
@Around("execution(* com.example..*(..))")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
// 前后增强逻辑
return pjp.proceed();
}
}
5.3 性能考量与模式取舍
- 对象创建开销:原型模式比频繁new对象更高效
- 内存占用:享元模式能大幅减少内存使用
- 运行时代价:代理模式会带来一定性能损耗
- 并发安全:单例模式要考虑线程安全问题
实测数据对比(仅供参考):
| 模式 | 对象创建时间 | 内存占用 | 线程安全 |
|---|---|---|---|
| 普通new | 1x | 1x | 不安全 |
| 原型模式 | 0.3x | 可变 | 看实现 |
| 工厂方法 | 1.2x | 1x | 安全实现 |
| 单例(枚举) | 1x | 极小 | 安全 |
6. 个人实践心得与推荐学习路径
从我的经验来看,掌握设计模式要经历三个阶段:
-
认知阶段(1-3个月):
- 重点理解SOLID原则
- 掌握3-5个最常用模式(单例、工厂、策略、观察者、装饰器)
- 推荐《Head First设计模式》入门
-
应用阶段(3-12个月):
- 在项目中刻意练习模式应用
- 学会识别模式适用场景
- 研究框架源码中的模式实现
- 推荐《设计模式:可复用面向对象软件的基础》
-
超越阶段(1年以上):
- 理解模式背后的设计原则
- 能灵活变通甚至组合模式
- 知道何时不该用模式
- 推荐《实现领域驱动设计》
最后分享一个实用技巧:在IDE中安装PlantUML插件,用类图记录你遇到的设计模式案例。我维护着一个持续更新的模式图库,这对理解和回忆各种模式特别有帮助。比如下面是观察者模式的PlantUML表示:
plantuml复制@startuml
interface Subject {
+registerObserver()
+removeObserver()
+notifyObservers()
}
interface Observer {
+update()
}
class ConcreteSubject {
-observers: List<Observer>
+registerObserver()
+removeObserver()
+notifyObservers()
}
class ConcreteObserver {
+update()
}
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
ConcreteSubject o-- Observer
@enduml