Java常用设计模式完整指南(含详细场景与实例)
一、创建型模式
1. 单例模式(Singleton)
具体应用场景与实例
| 应用场景 |
具体例子 |
为什么用单例 |
| 数据库连接池 |
HikariCP、Druid、C3P0 |
连接池管理全局数据库连接,避免频繁创建销毁 |
| 线程池 |
Executors创建的各类线程池 |
统一管理线程资源,控制并发数 |
| 配置中心 |
Spring的Environment、Apollo客户端 |
全局统一配置,避免重复读取配置文件 |
| 缓存管理 |
EhCache、Caffeine的CacheManager |
全局缓存实例,统一管理缓存生命周期 |
| 日志框架 |
Log4j的Logger、SLF4J的LoggerFactory
|
全局日志配置,统一输出格式和级别 |
| Spring Bean |
默认Scope为singleton的Bean |
容器管理的单例,节省内存,避免重复初始化 |
| 运行时环境 |
Runtime.getRuntime() |
JVM全局唯一运行时实例 |
实际代码示例
// ========== 数据库连接池单例(模拟HikariCP)==========
public class DataSourceManager {
private static final HikariDataSource DATA_SOURCE;
static {
// 类加载时初始化,JVM保证线程安全
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(20); // 最大连接数
DATA_SOURCE = new HikariDataSource(config);
}
private DataSourceManager() {}
public static Connection getConnection() throws SQLException {
return DATA_SOURCE.getConnection();
}
public static void close() {
DATA_SOURCE.close();
}
}
// 使用:全局获取连接
Connection conn = DataSourceManager.getConnection();
// ========== 配置中心单例(模拟Apollo)==========
public class AppConfig {
private static final AppConfig INSTANCE = new AppConfig();
private Properties properties = new Properties();
private AppConfig() {
// 加载配置文件
loadFromApollo();
}
public static AppConfig getInstance() {
return INSTANCE;
}
public String getString(String key) {
return properties.getProperty(key);
}
public int getInt(String key) {
return Integer.parseInt(properties.getProperty(key));
}
private void loadFromApollo() {
// 模拟从Apollo配置中心拉取配置
properties.setProperty("server.port", "8080");
properties.setProperty("redis.host", "localhost");
properties.setProperty("thread.pool.size", "10");
}
}
// 使用:全局统一访问配置
int port = AppConfig.getInstance().getInt("server.port");
String redisHost = AppConfig.getInstance().getString("redis.host");
2. 工厂模式(Factory)
具体应用场景与实例
| 应用场景 |
具体例子 |
为什么用工厂 |
| 支付系统 |
支付宝、微信、银联、Apple Pay |
统一支付入口,支持新支付方式热插拔 |
| 日志框架 |
Log4j、Logback、JDK Logging |
统一日志API,底层实现可切换 |
| 数据库方言 |
MyBatis的Dialect、Hibernate方言 |
适配不同数据库(MySQL/Oracle/PGSQL) |
| 文档导出 |
PDF、Excel、Word导出 |
统一导出接口,支持新格式扩展 |
| 消息推送 |
短信、邮件、App推送、微信模板消息 |
统一推送接口,根据场景选择渠道 |
| Spring Bean创建 |
BeanFactory、FactoryBean
|
容器统一管理对象生命周期 |
| 线程创建 |
ThreadFactory |
统一线程命名、优先级、异常处理 |
实际代码示例
// ========== 支付系统工厂(实际项目常用)==========
public interface PaymentChannel {
PayResult pay(Order order);
PayResult query(String orderId);
PayResult refund(String orderId, BigDecimal amount);
}
// 支付宝实现
public class AlipayChannel implements PaymentChannel {
private AlipayClient alipayClient; // 支付宝SDK客户端
public PayResult pay(Order order) {
AlipayTradePayRequest request = new AlipayTradePayRequest();
request.setBizContent("...");
AlipayTradePayResponse response = alipayClient.execute(request);
return new PayResult(response.isSuccess(), response.getTradeNo());
}
// ... query和refund实现
}
// 微信支付实现
public class WechatPayChannel implements PaymentChannel {
private WXPay wxPay; // 微信SDK
public PayResult pay(Order order) {
Map<String, String> resp = wxPay.unifiedOrder(buildParams(order));
return new PayResult("SUCCESS".equals(resp.get("return_code")), resp.get("prepay_id"));
}
}
// 支付工厂 - 根据支付方式创建对应渠道
public class PaymentFactory {
private static final Map<String, PaymentChannel> CHANNELS = new ConcurrentHashMap<>();
static {
CHANNELS.put("ALIPAY", new AlipayChannel());
CHANNELS.put("WECHAT", new WechatPayChannel());
CHANNELS.put("UNIONPAY", new UnionPayChannel());
}
public static PaymentChannel getChannel(String payType) {
PaymentChannel channel = CHANNELS.get(payType.toUpperCase());
if (channel == null) {
throw new UnsupportedPaymentException("不支持的支付方式: " + payType);
}
return channel;
}
// 支持动态注册新支付方式(插件化)
public static void registerChannel(String type, PaymentChannel channel) {
CHANNELS.put(type.toUpperCase(), channel);
}
}
// 使用:统一支付入口
public class OrderService {
public PayResult processPayment(Order order) {
// 根据用户选择获取对应支付渠道
PaymentChannel channel = PaymentFactory.getChannel(order.getPayType());
return channel.pay(order);
}
}
// ========== 文档导出工厂(报表系统常用)==========
public interface DocumentExporter {
void export(List<DataRow> data, OutputStream out);
String getContentType();
String getFileExtension();
}
// Excel导出
public class ExcelExporter implements DocumentExporter {
public void export(List<DataRow> data, OutputStream out) {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("数据");
// ... 填充数据
workbook.write(out);
}
public String getContentType() { return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; }
public String getFileExtension() { return "xlsx"; }
}
// PDF导出
public class PdfExporter implements DocumentExporter {
public void export(List<DataRow> data, OutputStream out) {
Document document = new Document();
PdfWriter.getInstance(document, out);
// ... 生成PDF表格
}
public String getContentType() { return "application/pdf"; }
public String getFileExtension() { return "pdf"; }
}
// CSV导出
public class CsvExporter implements DocumentExporter {
public void export(List<DataRow> data, OutputStream out) {
try (PrintWriter writer = new PrintWriter(out)) {
// 写入CSV头
writer.println("姓名,年龄,部门");
// 写入数据
for (DataRow row : data) {
writer.printf("%s,%d,%s%n", row.getName(), row.getAge(), row.getDept());
}
}
}
public String getContentType() { return "text/csv"; }
public String getFileExtension() { return "csv"; }
}
// 导出工厂
public class ExportFactory {
private static final Map<String, DocumentExporter> EXPORTERS = Map.of(
"excel", new ExcelExporter(),
"pdf", new PdfExporter(),
"csv", new CsvExporter()
);
public static DocumentExporter getExporter(String type) {
return EXPORTERS.getOrDefault(type.toLowerCase(), EXPORTERS.get("csv"));
}
}
// 使用:Controller层
@GetMapping("/export")
public void exportData(@RequestParam String type, HttpServletResponse response) throws IOException {
List<DataRow> data = dataService.queryAll();
DocumentExporter exporter = ExportFactory.getExporter(type);
response.setContentType(exporter.getContentType());
response.setHeader("Content-Disposition", "attachment; filename=data." + exporter.getFileExtension());
exporter.export(data, response.getOutputStream());
}
二、结构型模式
3. 代理模式(Proxy)
具体应用场景与实例
| 应用场景 |
具体例子 |
代理类型 |
解决的问题 |
| 日志记录 |
Spring AOP的@Log注解 |
JDK动态代理 |
无侵入记录方法入参出参 |
| 权限控制 |
Shiro、Spring Security的方法鉴权 |
JDK动态代理 |
方法级别的权限检查 |
| 事务管理 |
Spring的@Transactional
|
JDK动态代理/CGLIB |
自动开启/提交/回滚事务 |
| 性能监控 |
方法执行时间统计 |
JDK动态代理 |
埋点监控,不影响业务代码 |
| 延迟加载 |
MyBatis的Mapper接口 |
JDK动态代理 |
真正执行SQL时才访问数据库 |
| 远程调用 |
Dubbo、Feign客户端 |
JDK动态代理 |
本地调用像远程服务 |
| 连接池 |
Druid的PooledConnection
|
静态代理 |
连接归还池而非真正关闭 |
| 缓存 |
Spring Cache的@Cacheable
|
AOP代理 |
自动缓存方法返回值 |
实际代码示例
// ========== 性能监控代理(实际项目常用)==========
@Component
@Aspect // Spring AOP实现
public class PerformanceMonitorAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object monitor(ProceedingJoinPoint point) throws Throwable {
String methodName = point.getSignature().toShortString();
long start = System.currentTimeMillis();
try {
return point.proceed(); // 执行真实方法
} finally {
long cost = System.currentTimeMillis() - start;
if (cost > 1000) { // 慢查询预警
System.err.printf("【慢方法警告】%s 执行耗时: %dms%n", methodName, cost);
} else {
System.out.printf("【性能监控】%s 执行耗时: %dms%n", methodName, cost);
}
}
}
}
// 使用:业务代码完全无感知
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
// 自动被代理,记录性能
public Order getOrder(Long id) {
return orderMapper.selectById(id);
}
}
// ========== 远程调用代理(模拟Dubbo/Feign)==========
// 用户服务接口
public interface UserService {
@POST("/api/users")
User createUser(@Body User user);
@GET("/api/users/{id}")
User getUser(@Path("id") Long id);
}
// 动态代理实现远程调用
public class RpcProxy implements InvocationHandler {
private String baseUrl;
private OkHttpClient httpClient = new OkHttpClient();
public <T> T create(Class<T> clazz, String baseUrl) {
this.baseUrl = baseUrl;
return (T) Proxy.newProxyInstance(
clazz.getClassLoader(),
new Class<?>[]{clazz},
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 解析注解构建HTTP请求
String path = parsePath(method);
String url = baseUrl + path;
Request.Builder builder = new Request.Builder().url(url);
// 根据注解类型选择GET/POST
if (method.isAnnotationPresent(GET.class)) {
builder.get();
} else if (method.isAnnotationPresent(POST.class)) {
String json = new Gson().toJson(args[0]);
builder.post(RequestBody.create(json, JSON));
}
// 执行HTTP请求
Response response = httpClient.newCall(builder.build()).execute();
String result = response.body().string();
// 反序列化返回对象
return new Gson().fromJson(result, method.getReturnType());
}
}
// 使用:像调用本地方法一样调用远程服务
public class UserClient {
public static void main(String[] args) {
RpcProxy proxy = new RpcProxy();
UserService userService = proxy.create(UserService.class, "http://user-service:8080");
// 实际发送HTTP请求到远程服务
User user = userService.getUser(1001L);
System.out.println(user.getName());
}
}
// ========== 连接池代理(Druid的实现原理)==========
// 真实连接
public class RealConnection implements Connection {
public void close() {
// 真正关闭数据库连接
System.out.println("真正关闭数据库连接");
}
// ... 其他方法
}
// 连接代理 - 关键:close时不真正关闭,归还连接池
public class PooledConnection implements InvocationHandler {
private Connection realConnection;
private ConnectionPool pool;
private Connection proxyConnection; // 代理对象自己
public PooledConnection(Connection real, ConnectionPool pool) {
this.realConnection = real;
this.pool = pool;
// 创建代理对象
this.proxyConnection = (Connection) Proxy.newProxyInstance(
Connection.class.getClassLoader(),
new Class<?>[]{Connection.class},
this
);
}
public Connection getProxy() {
return proxyConnection;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
// 关键拦截:close方法不真正关闭,归还连接池
if ("close".equals(methodName)) {
pool.returnConnection(this); // 归还池子
System.out.println("【代理】连接归还连接池,而非真正关闭");
return null;
}
// 其他方法委托给真实连接
return method.invoke(realConnection, args);
}
}
// 使用:开发者调用close(),实际归还连接池
Connection conn = pool.getConnection();
// ... 使用连接
conn.close(); // 实际执行PooledConnection的代理逻辑,归还而非关闭
4. 装饰器模式(Decorator)
具体应用场景与实例
| 应用场景 |
具体例子 |
装饰内容 |
解决的问题 |
| Java IO流 |
BufferedInputStream包装FileInputStream
|
增加缓冲功能 |
减少系统调用次数,提高性能 |
| IO字符编码 |
InputStreamReader包装InputStream
|
增加编码转换 |
字节流→字符流,处理中文编码 |
| IO按行读取 |
BufferedReader包装Reader
|
增加行缓冲 |
支持readLine(),方便文本处理 |
| 压缩流 |
GZIPOutputStream包装FileOutputStream
|
增加压缩功能 |
写文件时自动压缩 |
| 加密流 |
CipherOutputStream |
增加加密功能 |
写数据时自动加密 |
| 集合同步 |
Collections.synchronizedList() |
增加线程安全 |
普通List变线程安全 |
| 集合不可修改 |
Collections.unmodifiableList() |
增加只读限制 |
防止外部修改内部数据 |
| UI组件 |
Java Swing的JScrollPane包装JTable
|
增加滚动条 |
表格内容过多时可滚动 |
| 咖啡/奶茶 |
星巴克订单系统 |
配料动态叠加 |
基础饮品+多种配料组合计价 |
实际代码示例
// ========== Java IO流的装饰器链(最经典例子)==========
public class IODecoratorDemo {
public static void main(String[] args) throws IOException {
// 原始组件:文件字节流
InputStream fileStream = new FileInputStream("data.txt");
// 第1层装饰:增加缓冲(减少系统调用)
InputStream bufferedStream = new BufferedInputStream(fileStream, 8192); // 8KB缓冲
// 第2层装饰:增加压缩解压
InputStream gzipStream = new GZIPInputStream(bufferedStream);
// 第3层装饰:字节转字符(指定编码)
Reader reader = new InputStreamReader(gzipStream, StandardCharsets.UTF_8);
// 第4层装饰:按行读取
BufferedReader lineReader = new BufferedReader(reader);
// 使用:从压缩的UTF-8编码文件中按行读取
String line;
while ((line = lineReader.readLine()) != null) {
System.out.println(line);
}
// 关闭最外层,内层自动级联关闭
lineReader.close();
}
}
// ========== 权限装饰器(数据访问层常用)==========
// 基础数据访问接口
public interface DataRepository {
List<Data> query(String condition);
void save(Data data);
}
// 基础实现
public class DatabaseRepository implements DataRepository {
public List<Data> query(String condition) {
// 执行SQL查询
return jdbcTemplate.query("SELECT * FROM data WHERE " + condition, ...);
}
public void save(Data data) {
jdbcTemplate.update("INSERT INTO data ...", ...);
}
}
// 装饰器基类
public abstract class RepositoryDecorator implements DataRepository {
protected DataRepository wrapped;
public RepositoryDecorator(DataRepository repo) { this.wrapped = repo; }
public List<Data> query(String condition) { return wrapped.query(condition); }
public void save(Data data) { wrapped.save(data); }
}
// 权限控制装饰器
public class SecurityDecorator extends RepositoryDecorator {
private CurrentUser user;
public SecurityDecorator(DataRepository repo, CurrentUser user) {
super(repo);
this.user = user;
}
@Override
public List<Data> query(String condition) {
// 添加数据权限过滤
String securedCondition = condition + " AND dept_id IN " + user.getAccessibleDepts();
System.out.println("【权限装饰】添加数据权限过滤: " + securedCondition);
return super.query(securedCondition);
}
@Override
public void save(Data data) {
// 检查是否有写入权限
if (!user.hasPermission("data:write")) {
throw new AccessDeniedException("无数据写入权限");
}
super.save(data);
}
}
// 缓存装饰器
public class CacheDecorator extends RepositoryDecorator {
private Cache<String, List<Data>> cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
public CacheDecorator(DataRepository repo) { super(repo); }
@Override
public List<Data> query(String condition) {
// 先查缓存
return cache.get(condition, key -> {
System.out.println("【缓存装饰】缓存未命中,查询数据库: " + key);
return super.query(key);
});
}
}
// 使用:动态叠加功能
DataRepository repo = new DatabaseRepository(); // 基础功能
repo = new SecurityDecorator(repo, currentUser); // 叠加权限控制
repo = new CacheDecorator(repo); // 叠加缓存
// 调用时自动执行权限检查→缓存查询→数据库查询
List<Data> result = repo.query("status=1");
// ========== 星巴克咖啡订单系统(经典教学案例)==========
// 组件接口
public interface Beverage {
String getDescription();
BigDecimal getCost();
}
// 基础饮品
public class Espresso implements Beverage {
public String getDescription() { return "浓缩咖啡"; }
public BigDecimal getCost() { return new BigDecimal("25.00"); }
}
public class DarkRoast implements Beverage {
public String getDescription() { return "深度烘焙咖啡"; }
public BigDecimal getCost() { return new BigDecimal("20.00"); }
}
// 装饰器基类
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage b) { this.beverage = b; }
public abstract String getDescription();
}
// 具体配料装饰器
public class Milk extends CondimentDecorator {
public Milk(Beverage b) { super(b); }
public String getDescription() { return beverage.getDescription() + " + 牛奶"; }
public BigDecimal getCost() { return beverage.getCost().add(new BigDecimal("3.00")); }
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage b) { super(b); }
public String getDescription() { return beverage.getDescription() + " + 摩卡"; }
public BigDecimal getCost() { return beverage.getCost().add(new BigDecimal("5.00")); }
}
public class Whip extends CondimentDecorator {
public Whip(Beverage b) { super(b); }
public String getDescription() { return beverage.getDescription() + " + 奶泡"; }
public BigDecimal getCost() { return beverage.getCost().add(new BigDecimal("2.50")); }
}
// 使用:自由组合订单
public class CoffeeShop {
public static void main(String[] args) {
// 订单1:浓缩咖啡 + 双份摩卡 + 奶泡
Beverage order1 = new Whip(new Mocha(new Mocha(new Espresso())));
System.out.println(order1.getDescription() + " = ¥" + order1.getCost());
// 输出:浓缩咖啡 + 摩卡 + 摩卡 + 奶泡 = ¥37.50
// 订单2:深度烘焙 + 牛奶 + 摩卡(大杯加价)
Beverage order2 = new Mocha(new Milk(new DarkRoast()));
System.out.println(order2.getDescription() + " = ¥" + order2.getCost());
// 输出:深度烘焙咖啡 + 牛奶 + 摩卡 = ¥28.00
}
}
三、行为型模式
5. 策略模式(Strategy)
具体应用场景与实例
| 应用场景 |
具体例子 |
策略 |
解决的问题 |
| 电商促销 |
双11、618、黑五活动 |
满减、折扣、秒杀、拼团 |
不同活动不同计价规则 |
| 会员等级 |
普通/银卡/金卡/钻石会员 |
不同折扣率、积分倍数 |
会员权益差异化 |
| 排序算法 |
Collections.sort() |
快速排序、归并排序、堆排序 |
根据数据规模选择最优算法 |
| 压缩算法 |
ZIP、GZIP、LZ4、Snappy |
不同压缩比和速度策略 |
根据场景选择压缩方案 |
| 图片处理 |
缩略图、水印、裁剪 |
不同处理算法 |
根据需求选择处理方式 |
| 路由算法 |
Dubbo负载均衡 |
随机、轮询、一致性哈希、最少活跃 |
根据服务状态选择调用策略 |
| 验证码 |
短信、邮件、图片、滑块 |
不同验证方式 |
根据安全等级选择验证策略 |
| 文件存储 |
本地、OSS、S3、FastDFS |
不同存储后端 |
根据文件类型选择存储位置 |
实际代码示例
// ========== 电商促销策略系统(实际项目)==========
// 策略接口
public interface PromotionStrategy {
String getName();
BigDecimal calculateDiscount(Order order); // 计算优惠金额
boolean isApplicable(Order order); // 是否适用该订单
}
// 具体策略1:满减促销
public class FullReductionStrategy implements PromotionStrategy {
private BigDecimal fullAmount; // 满多少
private BigDecimal reduction; // 减多少
public FullReductionStrategy(BigDecimal full, BigDecimal reduction) {
this.fullAmount = full;
this.reduction = reduction;
}
public String getName() { return "满" + fullAmount + "减" + reduction; }
public boolean isApplicable(Order order) {
return order.getTotalAmount().compareTo(fullAmount) >= 0;
}
public BigDecimal calculateDiscount(Order order) {
if (!isApplicable(order)) return BigDecimal.ZERO;
return reduction;
}
}
// 具体策略2:折扣促销
public class DiscountStrategy implements PromotionStrategy {
private BigDecimal discountRate; // 0.8 = 8折
public DiscountStrategy(BigDecimal rate) { this.discountRate = rate; }
public String getName() { return discountRate.multiply(new BigDecimal("10")) + "折"; }
public boolean isApplicable(Order order) { return true; } // 全场通用
public BigDecimal calculateDiscount(Order order) {
BigDecimal payAmount = order.getTotalAmount().multiply(discountRate);
return order.getTotalAmount().subtract(payAmount);
}
}
// 具体策略3:秒杀促销(限时限量)
public class SeckillStrategy implements PromotionStrategy {
private LocalDateTime startTime, endTime;
private int stock; // 库存
public boolean isApplicable(Order order) {
LocalDateTime now = LocalDateTime.now();
return now.isAfter(startTime) && now.isBefore(endTime) && stock > 0;
}
public BigDecimal calculateDiscount(Order order) {
// 秒杀价 = 原价 * 0.5
return order.getTotalAmount().multiply(new BigDecimal("0.5"));
}
}
// 具体策略4:拼团促销
public class GroupBuyStrategy implements PromotionStrategy {
private int minGroupSize; // 最低成团人数
public boolean isApplicable(Order order) {
return order.getGroupSize() >= minGroupSize;
}
public BigDecimal calculateDiscount(Order order) {
// 拼团价根据人数阶梯降价
int size = order.getGroupSize();
if (size >= 10) return order.getTotalAmount().multiply(new BigDecimal("0.3")); // 7折
if (size >= 5) return order.getTotalAmount().multiply(new BigDecimal("0.2")); // 8折
return order.getTotalAmount().multiply(new BigDecimal("0.1")); // 9折
}
}
// 策略上下文 - 促销引擎
@Component
public class PromotionEngine {
private List<PromotionStrategy> strategies = new ArrayList<>();
@Autowired
public PromotionEngine(List<PromotionStrategy> strategyList) {
this.strategies = strategyList; // Spring自动注入所有策略
}
// 为订单选择最优促销策略
public PromotionResult applyBestPromotion(Order order) {
PromotionResult bestResult = null;
BigDecimal maxDiscount = BigDecimal.ZERO;
for (PromotionStrategy strategy : strategies) {
if (strategy.isApplicable(order)) {
BigDecimal discount = strategy.calculateDiscount(order);
if (discount.compareTo(maxDiscount) > 0) {
maxDiscount = discount;
bestResult = new PromotionResult(strategy.getName(), discount);
}
}
}
return bestResult != null ? bestResult : new PromotionResult("无优惠", BigDecimal.ZERO);
}
// 叠加多个促销(如优惠券+满减)
public PromotionResult applyStackedPromotions(Order order, List<String> strategyNames) {
BigDecimal totalDiscount = BigDecimal.ZERO;
// ... 叠加计算逻辑
return new PromotionResult("叠加优惠", totalDiscount);
}
}
// 使用:Controller层
@RestController
public class OrderController {
@Autowired
private PromotionEngine promotionEngine;
@Autowired
private OrderService orderService;
@PostMapping("/order/preview")
public OrderPreviewVO previewOrder(@RequestBody OrderDTO dto) {
Order order = orderService.buildOrder(dto);
// 自动计算最优促销
PromotionResult promotion = promotionEngine.applyBestPromotion(order);
OrderPreviewVO vo = new OrderPreviewVO();
vo.setOriginalAmount(order.getTotalAmount());
vo.setDiscountAmount(promotion.getDiscount());
vo.setFinalAmount(order.getTotalAmount().subtract(promotion.getDiscount()));
vo.setPromotionName(promotion.getName());
return vo;
}
}
// ========== 负载均衡策略(Dubbo/Ribbon实现原理)==========
public interface LoadBalanceStrategy {
ServiceInstance select(List<ServiceInstance> instances, Invocation invocation);
}
// 随机策略
public class RandomStrategy implements LoadBalanceStrategy {
private Random random = new Random();
public ServiceInstance select(List<ServiceInstance> instances, Invocation invocation) {
int index = random.nextInt(instances.size());
return instances.get(index);
}
}
// 轮询策略
public class RoundRobinStrategy implements LoadBalanceStrategy {
private AtomicInteger counter = new AtomicInteger(0);
public ServiceInstance select(List<ServiceInstance> instances, Invocation invocation) {
int index = counter.getAndIncrement() % instances.size();
return instances.get(index);
}
}
// 一致性哈希(相同参数路由到相同节点)
public class ConsistentHashStrategy implements LoadBalanceStrategy {
private TreeMap<Long, ServiceInstance> virtualNodes = new TreeMap<>();
private static final int VIRTUAL_NODE_COUNT = 150;
public ServiceInstance select(List<ServiceInstance> instances, Invocation invocation) {
// 根据方法参数计算hash
String key = invocation.getMethodName() + invocation.getArguments().toString();
long hash = hash(key);
// 找到顺时针第一个虚拟节点
Map.Entry<Long, ServiceInstance> entry = virtualNodes.ceilingEntry(hash);
if (entry == null) entry = virtualNodes.firstEntry();
return entry.getValue();
}
}
// 最少活跃调用数(自动避让慢节点)
public class LeastActiveStrategy implements LoadBalanceStrategy {
public ServiceInstance select(List<ServiceInstance> instances, Invocation invocation) {
ServiceInstance best = null;
int leastActive = Integer.MAX_VALUE;
for (ServiceInstance instance : instances) {
int active = instance.getActiveCount(); // 当前进行中的调用数
if (active < leastActive) {
leastActive = active;
best = instance;
}
}
return best;
}
}
// 使用:Dubbo的负载均衡配置
@Reference(loadbalance = "leastactive") // 或 random/roundrobin/consistenthash
private UserService userService;
6. 观察者模式(Observer)
具体应用场景与实例
| 应用场景 |
具体例子 |
观察者 |
解决的问题 |
| Spring事件机制 |
ApplicationEventPublisher |
@EventListener |
解耦业务模块,如订单创建后发短信、扣库存、加积分 |
| 消息队列 |
Kafka、RabbitMQ的消费者 |
消费者组 |
广播消息给多个处理服务 |
| 配置中心 |
Nacos、Apollo的配置监听 |
客户端应用 |
配置变更实时推送 |
| 股票行情 |
同花顺、东方财富APP |
自选股列表 |
价格变动实时更新UI |
| 游戏系统 |
玩家状态变化 |
好友系统、排行榜、成就系统 |
一处变化多处响应 |
| 工作流引擎 |
审批流程状态变更 |
邮件通知、短信通知、待办推送 |
状态变更自动触发后续动作 |
| ZK节点监听 |
ZooKeeper的Watcher |
客户端 |
节点数据变化实时通知 |
| Redisson分布式锁 |
锁释放通知 |
等待线程 |
锁被释放时唤醒等待者 |
实际代码示例
// ========== Spring事件机制(最常用)==========
// 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
private Long orderId;
private Long userId;
private BigDecimal amount;
private LocalDateTime createTime;
public OrderCreatedEvent(Object source, Long orderId, Long userId, BigDecimal amount) {
super(source);
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
this.createTime = LocalDateTime.now();
}
// getters...
}
// 观察者1:发送短信通知
@Component
public class SmsNotificationListener {
@Autowired
private SmsService smsService;
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("【短信服务】订单" + event.getOrderId() + "创建成功,发送短信给用户" + event.getUserId());
smsService.send(event.getUserId(), "您的订单已创建,金额:" + event.getAmount());
}
}
// 观察者2:扣减库存
@Component
public class InventoryListener {
@Autowired
private InventoryService inventoryService;
@EventListener
@Async // 异步执行,不阻塞主流程
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("【库存服务】扣减订单" + event.getOrderId() + "的库存");
inventoryService.decreaseStock(event.getOrderId());
}
}
// 观察者3:增加用户积分
@Component
public class PointsListener {
@Autowired
private PointsService pointsService;
@EventListener
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) // 事务提交后才执行
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("【积分服务】订单" + event.getOrderId() + "增加积分");
int points = event.getAmount().intValue(); // 1元=1积分
pointsService.addPoints(event.getUserId(), points);
}
}
// 观察者4:记录操作日志
@Component
public class AuditLogListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("【审计日志】记录订单创建:" + event.getOrderId());
// 记录到ES或数据库
}
}
// 发布事件(主题)
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private OrderRepository orderRepository;
@Transactional
public Order createOrder(OrderDTO dto) {
// 1. 保存订单
Order order = new Order();
// ... 设置属性
orderRepository.save(order);
// 2. 发布事件(自动通知所有观察者)
OrderCreatedEvent event = new OrderCreatedEvent(this, order.getId(), order.getUserId(), order.getAmount());
eventPublisher.publishEvent(event);
// 3. 立即返回,后续处理异步执行
return order;
}
}
// ========== 配置中心实时推送(模拟Nacos)==========
// 配置主题
public class ConfigCenter {
private Map<String, String> configs = new ConcurrentHashMap<>();
private Map<String, List<ConfigListener>> listeners = new ConcurrentHashMap<>();
// 注册监听器
public void addListener(String dataId, ConfigListener listener) {
listeners.computeIfAbsent(dataId, k -> new CopyOnWriteArrayList<>()).add(listener);
}
// 发布配置变更
public void publishConfig(String dataId, String content) {
configs.put(dataId, content);
// 通知所有监听该配置的观察者
List<ConfigListener> list = listeners.get(dataId);
if (list != null) {
for (ConfigListener listener : list) {
listener.onConfigChange(dataId, content);
}
}
}
}
// 配置监听器接口
public interface ConfigListener {
void onConfigChange(String dataId, String content);
}
// 具体观察者1:数据库连接池动态刷新
public class DataSourceConfigListener implements ConfigListener {
private HikariDataSource dataSource;
public void onConfigChange(String dataId, String content) {
if ("db-config".equals(dataId)) {
System.out.println("【数据源】检测到数据库配置变更,动态刷新连接池");
// 解析新配置
Properties props = parseConfig(content);
// 动态调整连接池参数(无需重启)
dataSource.setMaximumPoolSize(Integer.parseInt(props.getProperty("maxPoolSize")));
dataSource.setConnectionTimeout(Long.parseLong(props.getProperty("connectionTimeout")));
}
}
}
// 具体观察者2:日志级别动态调整
public class LoggerConfigListener implements ConfigListener {
public void onConfigChange(String dataId, String content) {
if ("log-config".equals(dataId)) {
System.out.println("【日志系统】检测到日志级别变更,动态调整");
Map<String, String> config = parseConfig(content);
String rootLevel = config.get("root.level");
LoggerContext ctx = (LoggerContext) LoggerFactory.getILoggerFactory();
ctx.getLogger("ROOT").setLevel(Level.valueOf(rootLevel));
}
}
}
// 具体观察者3:业务开关(熔断、功能开关)
public class FeatureSwitchListener implements ConfigListener {
private Map<String, Boolean> featureSwitches = new ConcurrentHashMap<>();
public void onConfigChange(String dataId, String content) {
if ("feature-switches".equals(dataId)) {
System.out.println("【业务开关】刷新功能开关配置");
Map<String, String> switches = parseConfig(content);
switches.forEach((key, value) -> {
featureSwitches.put(key, Boolean.parseBoolean(value));
System.out.println(" - " + key + ": " + value);
});
}
}
public boolean isFeatureEnabled(String feature) {
return featureSwitches.getOrDefault(feature, false);
}
}
// 使用
public class ConfigDemo {
public static void main(String[] args) {
ConfigCenter configCenter = new ConfigCenter();
// 应用启动时注册监听器
configCenter.addListener("db-config", new DataSourceConfigListener());
configCenter.addListener("log-config", new LoggerConfigListener());
configCenter.addListener("feature-switches", new FeatureSwitchListener());
// 模拟配置中心推送变更
configCenter.publishConfig("db-config", "maxPoolSize=50\nconnectionTimeout=30000");
configCenter.publishConfig("feature-switches", "newPaymentGateway=true\nblackFridayMode=false");
}
}
7. 模板方法模式(Template Method)
具体应用场景与实例
| 应用场景 |
具体例子 |
固定骨架 |
可变步骤 |
| 数据导入 |
Excel/CSV/JSON导入 |
校验→解析→清洗→保存→日志 |
解析逻辑不同 |
| 报表导出 |
PDF/Excel/Word导出 |
查询数据→填充模板→生成文件→上传OSS |
模板填充方式不同 |
| 支付流程 |
支付宝/微信/银联支付 |
创建订单→调用渠道→处理回调→更新状态 |
调用渠道API不同 |
| 审批流程 |
请假/报销/入职审批 |
提交申请→逐级审批→通知结果→归档 |
审批规则不同 |
| JDBC操作 |
Spring的JdbcTemplate
|
获取连接→执行SQL→处理结果→释放资源 |
SQL和结果处理不同 |
| Servlet处理 |
HttpServlet的doGet/doPost |
接收请求→解析参数→业务处理→返回响应 |
业务逻辑不同 |
| 单元测试 |
JUnit的setUp→test→tearDown
|
初始化→执行测试→清理资源 |
测试用例不同 |
| 游戏AI |
不同难度级别的NPC |
感知→决策→行动 |
决策算法不同 |
实际代码示例
// ========== 数据导入模板(实际项目常用)==========
public abstract class DataImporter<T> {
// ========== 模板方法:final防止子类篡改流程 ==========
public final ImportResult importData(MultipartFile file, Long operatorId) {
List<T> records = new ArrayList<>();
List<String> errors = new ArrayList<>();
try {
// 1. 前置校验(固定)
validateFile(file);
// 2. 数据解析(抽象,子类实现)
records = parse(file.getInputStream());
// 3. 数据清洗(钩子,可选重写)
clean(records);
// 4. 业务校验(抽象,子类实现)
validateBusiness(records, errors);
if (!errors.isEmpty()) {
return ImportResult.fail(errors);
}
// 5. 数据转换(抽象)
List<Entity> entities = convert(records);
// 6. 批量保存(固定)
saveBatch(entities, operatorId);
// 7. 后置处理(钩子)
afterImport(entities, operatorId);
// 8. 记录日志(固定)
logImport(file.getOriginalFilename(), records.size(), operatorId);
return ImportResult.success(records.size());
} catch (Exception e) {
return ImportResult.fail("导入异常:" + e.getMessage());
}
}
// ========== 固定步骤 ==========
private void validateFile(MultipartFile file) {
if (file.isEmpty()) throw new IllegalArgumentException("文件不能为空");
String filename = file.getOriginalFilename();
if (!filename.matches(getFilePattern())) {
throw new IllegalArgumentException("不支持的文件格式");
}
}
private void saveBatch(List<Entity> entities, Long operatorId) {
// 使用MyBatis-Plus批量插入
service.saveBatch(entities, 500);
}
private void logImport(String filename, int count, Long operatorId) {
ImportLog log = new ImportLog();
log.setFileName(filename);
log.setRecordCount(count);
log.setOperatorId(operatorId);
log.setImportTime(LocalDateTime.now());
logService.save(log);
}
// ========== 抽象步骤:子类必须实现 ==========
protected abstract String getFilePattern(); // 文件格式正则
protected abstract List<T> parse(InputStream is); // 解析文件
protected abstract void validateBusiness(List<T> records, List<String> errors); // 业务校验
protected abstract List<Entity> convert(List<T> records); // 转换为实体
// ========== 钩子方法:子类可选重写 ==========
protected void clean(List<T> records) {
// 默认空实现:去除空行、trim等基础清洗
records.removeIf(Objects::isNull);
}
protected void afterImport(List<Entity> entities, Long operatorId) {
// 默认空实现
}
}
// ========== 具体实现1:员工Excel导入 ==========
@Component
public class EmployeeExcelImporter extends DataImporter<EmployeeRow> {
@Override
protected String getFilePattern() {
return ".*\\.xlsx?$";
}
@Override
protected List<EmployeeRow> parse(InputStream is) {
// 使用EasyExcel解析
return EasyExcel.read(is, EmployeeRow.class, new PageReadListener<>()).sheet().doReadSync();
}
@Override
protected void validateBusiness(List<EmployeeRow> records, List<String> errors) {
Set<String> idCards = new HashSet<>();
for (int i = 0; i < records.size(); i++) {
EmployeeRow row = records.get(i);
// 校验必填
if (StringUtils.isBlank(row.getName())) {
errors.add("第" + (i+1) + "行:姓名不能为空");
}
// 校验身份证唯一性
if (!idCards.add(row.getIdCard())) {
errors.add("第" + (i+1) + "行:身份证" + row.getIdCard() + "重复");
}
// 校验部门是否存在
if (!deptService.exists(row.getDeptCode())) {
errors.add("第" + (i+1) + "行:部门" + row.getDeptCode() + "不存在");
}
}
}
@Override
protected List<Entity> convert(List<EmployeeRow> records) {
return records.stream().map(row -> {
Employee emp = new Employee();
emp.setName(row.getName());
emp.setIdCard(row.getIdCard());
emp.setDeptId(deptService.getByCode(row.getDeptCode()).getId());
emp.setEntryDate(parseDate(row.getEntryDate()));
return emp;
}).collect(Collectors.toList());
}
@Override
protected void afterImport(List<Entity> entities, Long operatorId) {
// 发送入职欢迎邮件
for (Entity emp : entities) {
mailService.sendWelcomeEmail(((Employee)emp).getEmail());
}
}
}
// ========== 具体实现2:商品CSV导入 ==========
@Component
public class ProductCsvImporter extends DataImporter<ProductRow> {
@Override
protected String getFilePattern() {
return ".*\\.csv$";
}
@Override
protected List<ProductRow> parse(InputStream is) {
// 使用Apache Commons CSV解析
List<ProductRow> rows = new ArrayList<>();
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
CSVFormat format = CSVFormat.DEFAULT.withFirstRecordAsHeader();
for (CSVRecord record : format.parse(reader)) {
ProductRow row = new ProductRow();
row.setSku(record.get("SKU"));
row.setName(record.get("商品名称"));
row.setPrice(new BigDecimal(record.get("价格")));
rows.add(row);
}
return rows;
}
@Override
protected void clean(List<ProductRow> records) {
super.clean(records);
// 额外清洗:去除SKU前后空格,统一大写
for (ProductRow row : records) {
row.setSku(row.getSku().trim().toUpperCase());
}
}
@Override
protected void validateBusiness(List<ProductRow> records, List<String> errors) {
// 校验SKU唯一性、价格范围等
}
@Override
protected List<Entity> convert(List<ProductRow> records) {
// 转换为Product实体
}
}
// ========== 具体实现3:订单JSON导入(API对接)==========
@Component
public class OrderJsonImporter extends DataImporter<OrderRow> {
@Override
protected String getFilePattern() {
return ".*\\.json$";
}
@Override
protected List<OrderRow> parse(InputStream is) {
return new Gson().fromJson(new InputStreamReader(is), new TypeToken<List<OrderRow>>(){}.getType());
}
@Override
protected void afterImport(List<Entity> entities, Long operatorId) {
// 同步到ERP系统
for (Entity order : entities) {
erpService.syncOrder((Order)order);
}
}
// ... 其他实现
}
// 使用:Controller层统一入口
@RestController
public class ImportController {
@Autowired
private Map<String, DataImporter> importers; // Spring自动注入所有Importer
@PostMapping("/import/{type}")
public ImportResult importData(
@PathVariable String type,
@RequestParam MultipartFile file,
@RequestAttribute Long userId) {
DataImporter importer = importers.get(type + "Importer");
if (importer == null) {
throw new IllegalArgumentException("不支持的导入类型:" + type);
}
return importer.importData(file, userId);
}
}
// 请求:POST /import/employee 上传employee.xlsx
// 请求:POST /import/product 上传product.csv
// 请求:POST /import/order 上传order.json
// ========== 支付渠道模板(抽象支付流程)==========
public abstract class PaymentChannel {
// 模板方法:定义支付流程骨架
public final PayResult pay(Order order) {
// 1. 创建支付流水(固定)
PaymentRecord record = createPaymentRecord(order);
// 2. 调用渠道API(抽象,子类实现)
ChannelResponse response = callChannelAPI(order, record);
// 3. 处理响应(固定流程,部分细节抽象)
if (response.isSuccess()) {
record.setStatus("SUCCESS");
record.setChannelTradeNo(response.getTradeNo());
updateOrderStatus(order.getId(), "PAID");
// 钩子:支付成功后的扩展
onPaySuccess(order, record);
} else {
record.setStatus("FAILED");
record.setErrorMsg(response.getErrorMsg());
// 钩子:支付失败后的扩展
onPayFail(order, record, response);
}
// 4. 保存记录并返回(固定)
paymentRecordRepository.save(record);
return buildResult(record);
}
// 抽象步骤:调用具体渠道API
protected abstract ChannelResponse callChannelAPI(Order order, PaymentRecord record);
// 钩子方法:支付成功后的扩展点
protected void onPaySuccess(Order order, PaymentRecord record) {
// 默认:发送支付成功通知
notificationService.sendPaySuccessNotification(order.getUserId());
}
// 钩子方法:支付失败后的扩展点
protected void onPayFail(Order order, PaymentRecord record, ChannelResponse response) {
// 默认:记录失败日志
log.error("支付失败,订单:{},原因:{}", order.getId(), response.getErrorMsg());
}
// 固定步骤...
private PaymentRecord createPaymentRecord(Order order) { /* ... */ }
private void updateOrderStatus(Long orderId, String status) { /* ... */ }
private PayResult buildResult(PaymentRecord record) { /* ... */ }
}
// 支付宝实现
@Component
public class AlipayChannel extends PaymentChannel {
@Autowired
private AlipayClient alipayClient;
@Override
protected ChannelResponse callChannelAPI(Order order, PaymentRecord record) {
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setBizContent(buildBizContent(order, record));
try {
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
return new ChannelResponse(response.isSuccess(), response.getTradeNo(), null);
} catch (AlipayApiException e) {
return new ChannelResponse(false, null, e.getMessage());
}
}
@Override
protected void onPaySuccess(Order order, PaymentRecord record) {
super.onPaySuccess(order, record);
// 额外:支付宝积分发放
alipayPointService.grantPoints(order.getUserId(), calculatePoints(order.getAmount()));
}
}
// 微信支付实现
@Component
public class WechatPayChannel extends PaymentChannel {
@Autowired
private WXPay wxPay;
@Override
protected ChannelResponse callChannelAPI(Order order, PaymentRecord record) {
Map<String, String> params = new HashMap<>();
params.put("body", order.getProductName());
params.put("out_trade_no", record.getTradeNo());
params.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).intValue() + ""); // 分
params.put("spbill_create_ip", order.getClientIp());
params.put("notify_url", "https://example.com/notify/wechat");
params.put("trade_type", "NATIVE"); // 扫码支付
try {
Map<String, String> resp = wxPay.unifiedOrder(params);
boolean success = "SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"));
return new ChannelResponse(success, resp.get("prepay_id"), resp.get("err_code_des"));
} catch (Exception e) {
return new ChannelResponse(false, null, e.getMessage());
}
}
@Override
protected void onPayFail(Order order, PaymentRecord record, ChannelResponse response) {
super.onPayFail(order, record, response);
// 额外:微信特殊错误码处理
if ("NOTENOUGH".equals(response.getErrorCode())) {
// 余额不足,提示用户换卡
notificationService.sendInsufficientBalanceReminder(order.getUserId());
}
}
}
四、7种模式应用场景速查表
| 模式 |
典型应用场景 |
具体实例 |
解决的核心问题 |
| 单例 |
全局唯一资源管理 |
数据库连接池、线程池、配置中心、Spring Bean |
控制资源访问,避免重复创建 |
| 工厂 |
多种产品族的创建 |
支付渠道、文档导出、日志框架、负载均衡策略 |
解耦创建与使用,支持热插拔 |
| 代理 |
无侵入增强与控制 |
Spring AOP、MyBatis延迟加载、Dubbo远程调用、连接池 |
控制访问、增强功能、保护目标 |
| 装饰器 |
动态功能叠加 |
Java IO流、权限控制、缓存、咖啡配料 |
比继承更灵活的功能组合 |
| 策略 |
算法 interchangeable |
电商促销、会员等级、排序算法、负载均衡 |
消除if-else,运行时切换算法 |
| 观察者 |
一对多状态通知 |
Spring事件、配置中心、消息队列、股票行情 |
解耦发布订阅,自动广播通知 |
| 模板方法 |
固定流程+可变细节 |
数据导入、支付流程、报表导出、审批流程 |
复用骨架代码,开放扩展点 |
五、实际项目中的组合使用
场景:电商订单支付流程
订单创建
├── 发布 OrderCreatedEvent(观察者模式)
│ ├── 短信服务发送通知
│ ├── 库存服务扣减库存
│ └── 积分服务增加积分
│
└── 用户选择支付方式
│
├── 支付工厂创建支付渠道(工厂模式)
│ ├── 支付宝
│ ├── 微信支付
│ └── 银联支付
│
└── 执行支付(模板方法模式)
├── 固定:创建流水→调用渠道→更新状态
├── 抽象:调用支付宝/微信/银联API(策略模式)
└── 钩子:支付成功后的积分发放/优惠券赠送
支付结果处理
├── 异步通知接收(观察者模式)
└── 日志记录(代理模式增强)
这份文档涵盖了7种设计模式在实际项目中的40+个具体应用场景,每个场景都配有可直接使用的代码示例。