资讯详情

资讯详情

设计模式实战:从手撕单例到Spring应用

1. 设计模式入门为什么需要手撕刚入行那会儿我最怕面试官问设计模式。书上23种模式背得滚瓜烂熟但实际编码时却总用不对地方。直到有次重构老项目看到满屏的if-else和重复代码才真正理解《设计模式》扉页那句话发现变化封装变化。所谓手撕就是要像拆解机械钟表一样把每个模式的齿轮咬合关系彻底搞明白。我建议从这三个维度入手场景痛点什么情况下非用不可结构图示UML类图要能默写代码味道识别哪些坏味道可以用该模式解决比如看到多个if-else处理同类业务时就该条件反射想到策略模式遇到对象创建过程复杂时工厂模式就该浮现在脑海。这种肌肉记忆只能通过反复手写来实现。2. 单例模式的九种死法2.1 饿汉式的陷阱public class Singleton { private static Singleton instance new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } }看似完美的实现其实暗藏杀机类加载时就初始化可能拖慢启动速度如果构造方法抛异常实例将永远为空无法传递参数初始化比如需要配置文件路径实战经验Spring的Bean默认就是单例但它的实现远比这复杂解决了依赖注入、生命周期管理等诸多问题2.2 双重检查锁的坑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; } }volatile关键字在JDK1.5后才保证可见性之前版本仍可能拿到半初始化对象。现代JVM已经优化了synchronized性能简单用同步方法反而更可靠。3. 观察者模式的事件驱动实战3.1 自定义实现// 被观察者 class Subject { private ListObserver observers new ArrayList(); public void addObserver(Observer o) { observers.add(o); } public void changeState() { notifyObservers(); } private void notifyObservers() { observers.forEach(o - o.update()); } } // 观察者接口 interface Observer { void update(); }这种实现有几个常见问题同步通知可能阻塞主题线程没有区分事件类型观察者无法取消注册3.2 Spring Event改造// 定义事件 class OrderEvent extends ApplicationEvent { private String orderId; public OrderEvent(Object source, String orderId) { super(source); this.orderId orderId; } } // 发布事件 applicationContext.publishEvent(new OrderEvent(this, 12345)); // 监听事件 Component class OrderListener { EventListener public void handle(OrderEvent event) { // 处理订单逻辑 } }Spring的事件机制解决了线程模型、异常处理等生产级问题还支持异步事件Async事件过滤condition表达式监听器排序Order4. 装饰器模式与IO流设计4.1 JDK中的经典实现// 基础组件 public interface InputStream { int read() throws IOException; } // 具体组件 class FileInputStream implements InputStream { // 实现文件读取 } // 装饰器基类 class FilterInputStream implements InputStream { protected InputStream in; protected FilterInputStream(InputStream in) { this.in in; } public int read() throws IOException { return in.read(); } } // 具体装饰器 class BufferedInputStream extends FilterInputStream { public BufferedInputStream(InputStream in) { super(in); } // 添加缓冲功能 }这种设计精妙之处在于装饰器和具体组件实现相同接口可以多层嵌套比如缓冲解压加密运行时动态添加功能4.2 实际开发中的应用日志系统是典型场景// 基础日志接口 interface Logger { void log(String message); } // 装饰器基类 abstract class LoggerDecorator implements Logger { protected Logger logger; public LoggerDecorator(Logger logger) { this.logger logger; } } // 具体装饰器 class TimestampLogger extends LoggerDecorator { public TimestampLogger(Logger logger) { super(logger); } Override public void log(String message) { logger.log(LocalDateTime.now() message); } }这样就能灵活组合出带时间戳、JSON格式化、异步写入等特性的日志器。5. 模板方法模式的业务实践5.1 支付流程模板abstract class PaymentProcessor { // 模板方法 public final void process() { validate(); preProcess(); executePayment(); postProcess(); } protected abstract void validate(); protected void preProcess() { // 默认实现 } protected abstract void executePayment(); protected void postProcess() { // 默认实现 } } class AlipayProcessor extends PaymentProcessor { protected void validate() { // 支付宝特有验证 } protected void executePayment() { // 调用支付宝SDK } }关键点用final防止子类破坏流程钩子方法提供扩展点抽象方法强制子类实现5.2 JdbcTemplate的启示Spring的JdbcTemplate完美演绎了模板模式public T T execute(ConnectionCallbackT action) { Connection con DataSourceUtils.getConnection(getDataSource()); try { return action.doInConnection(con); } finally { DataSourceUtils.releaseConnection(con, getDataSource()); } }它帮我们处理了连接获取/释放异常转换事务管理 让我们只需关注SQL逻辑6. 策略模式的业务解耦6.1 传统if-else的痛点class OrderService { public void pay(String type) { if (alipay.equals(type)) { // 支付宝支付逻辑 } else if (wechat.equals(type)) { // 微信支付逻辑 } // 更多if... } }这种写法的问题违反开闭原则方法越来越长难以单元测试6.2 策略模式改造interface PaymentStrategy { void pay(BigDecimal amount); } class AlipayStrategy implements PaymentStrategy { public void pay(BigDecimal amount) { // 支付宝实现 } } class PaymentContext { private PaymentStrategy strategy; public PaymentContext(PaymentStrategy strategy) { this.strategy strategy; } public void execute(BigDecimal amount) { strategy.pay(amount); } } // 使用 new PaymentContext(new AlipayStrategy()).execute(new BigDecimal(100));Spring中可以用更优雅的方式Service public class PaymentService { Autowired private MapString, PaymentStrategy strategies; public void pay(String type, BigDecimal amount) { strategies.get(type).pay(amount); } }结合Qualifier或自定义注解可以实现更灵活的策略路由7. 工厂模式的演进之路7.1 简单工厂的局限class AnimalFactory { public static Animal create(String type) { switch (type) { case dog: return new Dog(); case cat: return new Cat(); default: throw new IllegalArgumentException(); } } }当新增类型时必须修改工厂类违反OCP原则7.2 工厂方法模式interface AnimalFactory { Animal create(); } class DogFactory implements AnimalFactory { public Animal create() { return new Dog(); } }每个产品对应一个工厂符合单一职责原则。Spring中的FactoryBean就是典型应用7.3 抽象工厂模式interface GUIFactory { Button createButton(); Menu createMenu(); } class WinFactory implements GUIFactory { public Button createButton() { return new WinButton(); } public Menu createMenu() { return new WinMenu(); } }适合创建产品族比如不同风格的UI组件8. 代理模式与Spring AOP8.1 静态代理的束缚interface UserService { void save(); } class UserServiceImpl implements UserService { public void save() { // 业务逻辑 } } class UserServiceProxy implements UserService { private UserService target; public UserServiceProxy(UserService target) { this.target target; } public void save() { System.out.println(before); target.save(); System.out.println(after); } }每个方法都要手动增强维护成本高8.2 JDK动态代理class LogInvocationHandler implements InvocationHandler { private Object target; public LogInvocationHandler(Object target) { this.target target; } public Object invoke(Object proxy, Method method, Object[] args) { System.out.println(before method.getName()); Object result method.invoke(target, args); System.out.println(after method.getName()); return result; } } UserService proxy (UserService) Proxy.newProxyInstance( loader, new Class[]{UserService.class}, new LogInvocationHandler(target) );基于接口实现通过反射调用目标方法8.3 CGLIB字节码增强Enhancer enhancer new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { System.out.println(before); Object result proxy.invokeSuper(obj, args); System.out.println(after); return result; } }); UserService proxy (UserService) enhancer.create();不需要接口直接继承目标类。Spring AOP默认对接口用JDK代理对类用CGLIB9. 建造者模式的正确姿势9.1 重叠构造器陷阱class NutritionFacts { private int servingSize; // required private int servings; // required private int calories; // optional // 更多字段... public NutritionFacts(int servingSize, int servings) { this(servingSize, servings, 0); } public NutritionFacts(int servingSize, int servings, int calories) { // 更多构造器... } }当可选参数多时构造器数量会爆炸9.2 Builder模式实现class NutritionFacts { private final int servingSize; private final int servings; private final int calories; public static class Builder { // 必选参数 private final int servingSize; private final int servings; // 可选参数 private int calories 0; public Builder(int servingSize, int servings) { this.servingSize servingSize; this.servings servings; } public Builder calories(int val) { calories val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servingSize builder.servingSize; servings builder.servings; calories builder.calories; } } // 使用 NutritionFacts cocaCola new NutritionFacts.Builder(240, 8) .calories(100) .build();这种实现保证了不可变对象链式调用参数可读性强10. 设计模式混搭实战10.1 Spring中的模式组合以Transactional注解为例代理模式AOP实现模板方法事务模板策略模式不同传播机制工厂模式PlatformTransactionManager10.2 电商优惠券系统设计// 策略模式计算折扣 interface DiscountStrategy { BigDecimal apply(BigDecimal price); } // 装饰器模式叠加优惠 class CouponDecorator implements DiscountStrategy { private DiscountStrategy strategy; private BigDecimal couponAmount; public CouponDecorator(DiscountStrategy strategy, BigDecimal couponAmount) { this.strategy strategy; this.couponAmount couponAmount; } public BigDecimal apply(BigDecimal price) { return strategy.apply(price).subtract(couponAmount); } } // 工厂模式创建策略 class StrategyFactory { public static DiscountStrategy create(String type) { switch (type) { case VIP: return new VipDiscount(); case NEWUSER: return new NewUserDiscount(); default: return new NoDiscount(); } } } // 使用 DiscountStrategy strategy new CouponDecorator( StrategyFactory.create(VIP), new BigDecimal(10) ); BigDecimal finalPrice strategy.apply(new BigDecimal(100));设计模式不是银弹但确实是工程师的必备工具。我的经验是先写烂代码再思考如何用模式重构。当你看着自己的代码感到恶心时就是进步的开始。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →