Java常用设计模式完整指南(含详细场景与实例)

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创建 BeanFactoryFactoryBean 容器统一管理对象生命周期
线程创建 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的setUptesttearDown 初始化→执行测试→清理资源 测试用例不同
游戏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+个具体应用场景,每个场景都配有可直接使用的代码示例。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容