使用策略模式 + 自动注册机制来构建旅游点评系统的搜索模块
✅ 目标:
- 搜索模块支持不同内容类型(攻略、达人、游记等)
- 每种搜索逻辑用一个策略类表示
- 自动注册(基于注解 + Spring 容器)
- 新增搜索类型时,只需添加一个类 + 一个注解,无需改工厂、注册表等!
🛠️ 技术方案:
- Spring Boot
- 自定义注解
@SearchType("guide")
进行标记 - 启动时由 Spring 自动扫描并注册到
Map<String, SearchStrategy>
📁 项目结构如下(Spring Boot)
search-system-springboot/
├── SearchSystemApplication.java
├── annotation/
│ └── SearchType.java
├── strategy/
│ ├── SearchStrategy.java
│ ├── GuideSearch.java
│ ├── ExpertSearch.java
│ ├── TravelNoteSearch.java
│ └── SearchStrategyFactory.java
└── controller/└── SearchController.java
✅ 关键文件内容如下:
🔹 SearchStrategy.java
(策略接口)
package strategy;public interface SearchStrategy {void search(String keyword);
}
🔹 @SearchType
注解(用于标记策略类型)
package annotation;import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SearchType {String value(); // 类型名称,如 "guide"
}
🔹 SearchStrategyFactory.java
(策略注册器)
package strategy;import annotation.SearchType;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;@Component
public class SearchStrategyFactory {@Autowiredprivate ApplicationContext context;private final Map<String, SearchStrategy> strategyMap = new HashMap<>();@PostConstructpublic void init() {Map<String, Object> beans = context.getBeansWithAnnotation(SearchType.class);for (Object bean : beans.values()) {Class<?> clazz = bean.getClass();SearchType annotation = clazz.getAnnotation(SearchType.class);String type = annotation.value().toLowerCase();strategyMap.put(type, (SearchStrategy) bean);}}public SearchStrategy getStrategy(String type) {SearchStrategy strategy = strategyMap.get(type.toLowerCase());if (strategy == null) {throw new IllegalArgumentException("不支持的搜索类型: " + type);}return strategy;}
}
🔹 示例策略类 GuideSearch.java
package strategy;import annotation.SearchType;
import org.springframework.stereotype.Component;@Component
@SearchType("guide")
public class GuideSearch implements SearchStrategy {public void search(String keyword) {System.out.println("搜索攻略:" + keyword);}
}
🔹 示例策略类 ExpertSearch.java
package strategy;import annotation.SearchType;
import org.springframework.stereotype.Component;@Component
@SearchType("expert")
public class ExpertSearch implements SearchStrategy {public void search(String keyword) {System.out.println("搜索达人:" + keyword);}
}
🔹 控制器 SearchController.java
package controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import strategy.SearchStrategy;
import strategy.SearchStrategyFactory;@RestController
@RequestMapping("/search")
public class SearchController {@Autowiredprivate SearchStrategyFactory factory;@GetMappingpublic String search(@RequestParam String type, @RequestParam String keyword) {SearchStrategy strategy = factory.getStrategy(type);strategy.search(keyword);return "搜索成功:" + type + " -> " + keyword;}
}
🔹 启动类 SearchSystemApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SearchSystemApplication {public static void main(String[] args) {SpringApplication.run(SearchSystemApplication.class, args);}
}
✅ 如何运行:
- 新建 Spring Boot 项目(Maven/Gradle 都可以)
- 创建上述包和类(
annotation
、strategy
、controller
) - 启动项目后访问:
http://localhost:8080/search?type=guide&keyword=台北夜市
输出:
搜索攻略:台北夜市
🚀 如何新增一个搜索类型?
比如新增 TravelNoteSearch
:
@Component
@SearchType("travelnote")
public class TravelNoteSearch implements SearchStrategy {public void search(String keyword) {System.out.println("搜索游记:" + keyword);}
}
就完事了,无需改动任何已有类!开闭原则 ✔️