《设计模式实战:Spring中的模式应用》

68 阅读4分钟

设计模式实战:Spring中的模式应用

一、工厂模式:Spring就像一个大工厂

1.1 现实工厂类比

想象你去奶茶店点单: 你告诉店员要"珍珠奶茶"(getBean("pearlMilkTea")) 店员(Spring容器)根据配方制作奶茶 你不用关心奶茶是怎么做的

1.2 具体代码示例

// 定义产品接口
public interface MilkTea {
    String getName();
}

// 具体产品
@Component("pearlMilkTea")
public class PearlMilkTea implements MilkTea {
    public String getName() { return "珍珠奶茶"; }
}

// 在Controller中使用
@RestController
public class OrderController {
    @Autowired  // 自动从工厂获取
    private MilkTea milkTea;
    
    @GetMapping("/order")
    public String order() {
        return "你点的饮料是:" + milkTea.getName();
    }
}

二、单例模式:节省资源的妙招

2.1 单例就像公司的打印机

全公司共用一台打印机(单例) 需要打印时去前台取用(getBean) 避免每个员工都买打印机(节省资源)

2.2 Spring单例示例

@Service  // 默认就是单例
public class PrinterService {
    private int printCount = 0;
    
    public void print(String document) {
        System.out.println("正在打印第" + (++printCount) + "份文件:" + document);
    }
}

// 测试
@RestController
public class TestController {
    @Autowired PrinterService printer1;
    @Autowired PrinterService printer2;
    
    @GetMapping("/test")
    public String test() {
        printer1.print("年度报告");
        printer2.print("会议记录");
        return "打印完成,printer1==printer2:" + (printer1 == printer2);
    }
}
// 输出:true,说明是同一个实例

三、代理模式:AOP的魔法披风

3.1 代理就像明星的经纪人

你想联系明星(调用目标方法) 必须先通过经纪人(代理对象) 经纪人可以: 安排见面时间(前置增强) 记录谈话内容(后置增强) 拒绝不合理请求(权限控制)

3.2 Spring AOP实战

java

// 1. 定义切面(经纪人规则)
@Aspect
@Component
public class LogAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeLog(JoinPoint jp) {
        System.out.println("准备调用:" + jp.getSignature().getName());
    }
}

// 2. 业务类(明星)
@Service
public class UserService {
    public void addUser(String name) {
        System.out.println("添加用户:" + name);
    }
}

// 3. 测试
@RestController
public class UserController {
    @Autowired UserService userService;
    
    @GetMapping("/add")
    public String addUser() {
        userService.addUser("张三");
        return "添加成功";
    }
}

// 控制台输出:
// 准备调用:addUser
// 添加用户:张三

四、观察者模式:事件通知系统

4.1 就像微信订阅号

你关注了某个公众号(注册监听器) 公众号发布新文章(发布事件) 所有粉丝都会收到通知(通知监听器)

4.2 Spring事件示例

// 1. 定义事件(新文章)
public class NewArticleEvent extends ApplicationEvent {
    private String title;
    public NewArticleEvent(Object source, String title) {
        super(source);
        this.title = title;
    }
    public String getTitle() { return title; }
}

// 2. 发布者(公众号)
@Service
public class PublisherService {
    @Autowired ApplicationEventPublisher publisher;
    
    public void publishArticle(String title) {
        System.out.println("发布新文章:" + title);
        publisher.publishEvent(new NewArticleEvent(this, title));
    }
}

// 3. 订阅者(粉丝)
@Component
public class Subscriber {
    @EventListener
    public void handleEvent(NewArticleEvent event) {
        System.out.println("收到新文章通知:" + event.getTitle());
    }
}

// 4. 测试
@RestController
public class TestController {
    @Autowired PublisherService publisher;
    
    @GetMapping("/publish")
    public String publish() {
        publisher.publishArticle("Spring设计模式详解");
        return "发布成功";
    }
}

// 控制台输出:
// 发布新文章:Spring设计模式详解
// 收到新文章通知:Spring设计模式详解

五、模板方法模式:流程固定,细节可变

5.1 就像泡茶的固定步骤

烧水(固定) 放茶叶(可变) 倒水(固定) 加料(可变) 搅拌(固定)

5.2 Spring JdbcTemplate示例

// 传统JDBC vs Spring模板方法
public class UserDao {
    // 传统方式(需要自己处理所有步骤)
    public User findUser(Long id) throws SQLException {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = dataSource.getConnection();
            stmt = conn.prepareStatement("SELECT * FROM users WHERE id=?");
            stmt.setLong(1, id);
            rs = stmt.executeQuery();
            if (rs.next()) {
                return new User(rs.getLong("id"), rs.getString("name"));
            }
            return null;
        } finally {
            // 需要手动关闭所有资源
            if (rs != null) rs.close();
            if (stmt != null) stmt.close();
            if (conn != null) conn.close();
        }
    }

    // Spring模板方法方式(只需关注核心逻辑)
    @Autowired JdbcTemplate jdbcTemplate;
    
    public User findUserEasy(Long id) {
        return jdbcTemplate.queryForObject(
            "SELECT * FROM users WHERE id=?",
            (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name")),
            id);
    }
}

六、设计模式记忆口诀

模式名称口诀Spring应用示例
工厂模式"想要对象不用new,工厂里面拿就有"BeanFactory
单例模式"全局只用一实例,节省资源又省事"@Service默认单例
代理模式"想要访问先过岗,代理帮你把事挡"Spring AOP
观察者"事件发生就通知,所有监听都知情"ApplicationEvent
模板方法"固定流程不变更,具体实现可调整"JdbcTemplate

七、常见问题解答

Q:为什么要用设计模式? A:就像建房子有标准施工流程:

  • 使代码更规范(施工标准化)
  • 更易维护(维修方便)
  • 更易扩展(加层改造容易)

Q:Spring用了这么多模式,会不会很复杂? A:就像智能手机: 内部很复杂(各种芯片、传感器) 但用起来很简单(触摸屏操作) Spring也是这样,内部复杂但API简单 Q:怎么记住这些模式? A:多联系现实生活:

  • 工厂模式 ≈ 奶茶店
  • 单例模式 ≈ 公司打印机
  • 代理模式 ≈ 明星经纪人
  • 观察者 ≈ 微信订阅号
  • 模板方法 ≈ 泡茶流程

记住:设计模式不是银弹,合适最重要!就像你不能用泡茶的流程去煮咖啡(虽然都是饮品),要根据实际需求选择合适的模式。