设计模式

1、装饰器模式

/**
   核心: 通过组合而非继承,在不修改原接口的情况下,动态扩展功能。解决了“类膨胀”的问题。
   
   组件:   
         Component(组件接口):定义对象的基本接口
         ConcreteComponent(具体组件):实现基本接口的原始对象 (自己干活)
         Decorator(装饰器抽象类):持有Component引用,并实现相同接口 (转交给别人干活)
         ConcreteDecorator(具体装饰器):扩展Decorator,添加具体功能 (转交给别人干活,同时自己也干点活)
   
   原理:装饰器对象包装原始对象,形成装饰器链。每个装饰器都可以在调用原始方法前后添加自己的逻辑,然后将调用传递给下一个对象。 
   
   优势:
         开闭原则:对扩展开放,对修改关闭
         灵活性:可以任意组合多个装饰器
         职责分离:每个装饰器只负责一个特定功能
         运行时扩展:可以在运行时动态添加或移除功能
    
    应用场景:     
        输入输出流处理(如Java的BufferedReader包装FileReader)
        中间件系统(如Express.js中间件)
        权限验证、日志记录、缓存等横切关注点(Spring AOP)
        Servlet Filter请求过滤器链
        
**/
咖啡订单系统
/**
    问题:需要支持各种配料组合(牛奶、糖、奶泡等)
    解决:每种配料作为一个装饰器,可以任意组合
    优势:避免创建大量子类(如MilkSugarCoffee、MilkCoffee等)
**/

// 场景:咖啡订单系统 - 动态添加配料
interface Coffee {
    String getDescription();
    double getCost();
}

class SimpleCoffee implements Coffee {
    public String getDescription() {
        return "Simple Coffee";
    }
    
    public double getCost() {
        return 2.0;
    }
}

abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    
    public String getDescription() {
        return coffee.getDescription();
    }
    
    public double getCost() {
        return coffee.getCost();
    }
}

class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }
    
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }
    
    public double getCost() {
        return coffee.getCost() + 0.2;
    }
}

实际业务场景

数据连接池

查看代码
// 1. 基础连接接口
interface DatabaseConnection {
    ResultSet executeQuery(String sql) throws SQLException;
    int executeUpdate(String sql) throws SQLException;
    void close() throws SQLException;
}

// 2. 真实数据库连接
class RealConnection implements DatabaseConnection {
    private Connection conn;
    private String id;
    
    public RealConnection(String url, String user, String pwd) throws SQLException {
        this.conn = DriverManager.getConnection(url, user, pwd);
        this.id = "CONN-" + System.currentTimeMillis();
    }
    
    public ResultSet executeQuery(String sql) throws SQLException {
        return conn.createStatement().executeQuery(sql);
    }
    
    public int executeUpdate(String sql) throws SQLException {
        return conn.createStatement().executeUpdate(sql);
    }
    
    public void close() throws SQLException {
        if (conn != null) conn.close();
    }
    
    public String getId() { return id; }
}

// 3. 装饰器基类
abstract class ConnectionDecorator implements DatabaseConnection {
    protected DatabaseConnection connection;
    
    public ConnectionDecorator(DatabaseConnection conn) {
        this.connection = conn;
    }
    
    public ResultSet executeQuery(String sql) throws SQLException {
        return connection.executeQuery(sql);
    }
    
    public int executeUpdate(String sql) throws SQLException {
        return connection.executeUpdate(sql);
    }
    
    public void close() throws SQLException {
        connection.close();
    }
}

// 4. 连接池装饰器(核心)
class PooledConnection extends ConnectionDecorator {
    private ConnectionPool pool;
    private boolean inPool = false;
    
    public PooledConnection(DatabaseConnection conn, ConnectionPool pool) {
        super(conn);
        this.pool = pool;
    }
    
    @Override
    public void close() throws SQLException {
        if (!inPool) {
            inPool = true;
            pool.returnConnection(this);  // 返回池中,不真正关闭
        }
    }
    
    public void realClose() throws SQLException {
        super.close();  // 真正关闭连接
    }
    
    public void reset() {
        inPool = false;
    }
}

// 5. 监控装饰器
class MonitoringDecorator extends ConnectionDecorator {
    private AtomicInteger queryCount = new AtomicInteger(0);
    private AtomicLong totalTime = new AtomicLong(0);
    
    public MonitoringDecorator(DatabaseConnection conn) {
        super(conn);
    }
    
    @Override
    public ResultSet executeQuery(String sql) throws SQLException {
        long start = System.currentTimeMillis();
        try {
            return super.executeQuery(sql);
        } finally {
            queryCount.incrementAndGet();
            totalTime.addAndGet(System.currentTimeMillis() - start);
        }
    }
    
    public void printStats() {
        System.out.println("查询次数: " + queryCount + ", 总耗时: " + totalTime + "ms");
    }
}

// 6. 缓存装饰器
class CachedConnection extends ConnectionDecorator {
    private Map<String, ResultSet> cache = new ConcurrentHashMap<>();
    
    public CachedConnection(DatabaseConnection conn) {
        super(conn);
    }
    
    @Override
    public ResultSet executeQuery(String sql) throws SQLException {
        if (cache.containsKey(sql)) {
            System.out.println("缓存命中: " + sql);
            return cache.get(sql);
        }
        
        ResultSet rs = super.executeQuery(sql);
        cache.put(sql, rs);
        return rs;
    }
    
    @Override
    public int executeUpdate(String sql) throws SQLException {
        cache.clear();  // 更新时清空缓存
        return super.executeUpdate(sql);
    }
}

// 7. 连接池实现
class ConnectionPool {
    private final BlockingQueue<PooledConnection> available = new LinkedBlockingQueue<>();
    private final Set<PooledConnection> used = ConcurrentHashMap.newKeySet();
    private final String url, user, pwd;
    private final int maxSize;
    
    public ConnectionPool(String url, String user, String pwd, int maxSize) {
        this.url = url; this.user = user; this.pwd = pwd; this.maxSize = maxSize;
        
        // 预创建连接
        for (int i = 0; i < maxSize / 2; i++) {
            try {
                available.offer(new PooledConnection(new RealConnection(url, user, pwd), this));
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    public DatabaseConnection getConnection() throws SQLException {
        PooledConnection conn = available.poll();
        if (conn == null && used.size() < maxSize) {
            conn = new PooledConnection(new RealConnection(url, user, pwd), this);
        }
        if (conn == null) {
            throw new SQLException("连接池已满");
        }
        
        conn.reset();
        used.add(conn);
        return conn;
    }
    
    public void returnConnection(PooledConnection conn) {
        if (used.remove(conn)) {
            available.offer(conn);
        }
    }
    
    public void shutdown() {
        available.forEach(conn -> {
            try { conn.realClose(); } catch (SQLException e) { e.printStackTrace(); }
        });
        used.forEach(conn -> {
            try { conn.realClose(); } catch (SQLException e) { e.printStackTrace(); }
        });
    }
}

// 8. 连接工厂
class ConnectionFactory {
    private ConnectionPool pool;
    
    public ConnectionFactory(String url, String user, String pwd, int poolSize) {
        this.pool = new ConnectionPool(url, user, pwd, poolSize);
    }
    
    public DatabaseConnection create(String type) throws SQLException {
        DatabaseConnection conn = pool.getConnection();
        
        switch (type) {
            case "monitored":
                return new MonitoringDecorator(conn);
            case "cached":
                return new CachedConnection(conn);
            case "enterprise":
                return new MonitoringDecorator(new CachedConnection(conn));
            default:
                return conn;
        }
    }
    
    public void shutdown() { pool.shutdown(); }
}

// 9. 使用示例
public class ConnectionPoolExample {
    public static void main(String[] args) throws SQLException {
        ConnectionFactory factory = new ConnectionFactory("jdbc:h2:mem:test", "sa", "", 5);
        
        // 普通连接
        DatabaseConnection basic = factory.create("basic");
        basic.close();
        
        // 企业级连接(监控+缓存)
        DatabaseConnection enterprise = factory.create("enterprise");
        enterprise.close();
        
        factory.shutdown();
    }
}

Spring AOP

查看代码
// 1. 业务接口
interface UserService {
    User getUserById(Long id);
    void updateUser(User user);
    void deleteUser(Long id);
}

// 2. 核心业务实现
@Service
public class UserServiceImpl implements UserService {
    
    @Override
    public User getUserById(Long id) {
        // 模拟数据库查询
        System.out.println("从数据库查询用户: " + id);
        return new User(id, "User" + id, "user" + id + "@example.com");
    }
    
    @Override
    public void updateUser(User user) {
        System.out.println("更新用户: " + user.getName());
        // 模拟更新操作
    }
    
    @Override
    public void deleteUser(Long id) {
        System.out.println("删除用户: " + id);
        // 模拟删除操作
    }
}

// 3. 用户实体
class User {
    private Long id;
    private String name;
    private String email;
    
    public User(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
    
    // getters and setters
    public Long getId() { return id; }
    public String getName() { return name; }
    public String getEmail() { return email; }
}

// 4. 性能监控装饰器 - 通过AOP实现
@Aspect
@Component
public class PerformanceMonitoringAspect {
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        long startTime = System.currentTimeMillis();
        Object result = null;
        
        try {
            System.out.println("🔍 [性能监控] 开始执行: " + className + "." + methodName);
            result = joinPoint.proceed();
            return result;
        } finally {
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            System.out.println("⏱️ [性能监控] " + className + "." + methodName + " 执行耗时: " + duration + "ms");
        }
    }
}

// 5. 缓存装饰器 - 通过AOP实现
@Aspect
@Component
public class CacheAspect {
    
    private final Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
    private final long CACHE_EXPIRE_TIME = 30000; // 30秒
    
    @Around("execution(* com.example.service.*.get*(..))")
    public Object cacheGet(ProceedingJoinPoint joinPoint) throws Throwable {
        String cacheKey = generateCacheKey(joinPoint);
        
        // 检查缓存
        CacheEntry entry = cache.get(cacheKey);
        if (entry != null && !entry.isExpired()) {
            System.out.println("✅ [缓存命中] " + cacheKey);
            return entry.getValue();
        }
        
        // 执行原方法
        Object result = joinPoint.proceed();
        
        // 存入缓存
        cache.put(cacheKey, new CacheEntry(result, System.currentTimeMillis() + CACHE_EXPIRE_TIME));
        System.out.println("💾 [缓存存储] " + cacheKey);
        
        return result;
    }
    
    @After("execution(* com.example.service.*.update*(..) || execution(* com.example.service.*.delete*(..))")
    public void clearCache() {
        cache.clear();
        System.out.println("🗑️ [缓存清理] 数据变更,清空缓存");
    }
    
    private String generateCacheKey(ProceedingJoinPoint joinPoint) {
        StringBuilder key = new StringBuilder();
        key.append(joinPoint.getTarget().getClass().getSimpleName())
           .append(".")
           .append(joinPoint.getSignature().getName());
        
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            key.append("(");
            for (int i = 0; i < args.length; i++) {
                if (i > 0) key.append(",");
                key.append(args[i]);
            }
            key.append(")");
        }
        
        return key.toString();
    }
    
    private static class CacheEntry {
        private Object value;
        private long expireTime;
        
        public CacheEntry(Object value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
        }
        
        public boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
        
        public Object getValue() {
            return value;
        }
    }
}

// 6. 日志装饰器
@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        
        System.out.println("📝 [日志] 方法调用: " + methodName + ", 参数: " + Arrays.toString(args));
    }
    
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("✅ [日志] 方法成功: " + methodName + ", 返回值: " + result);
    }
    
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("❌ [日志] 方法异常: " + methodName + ", 异常: " + ex.getMessage());
    }
}

// 7. 事务装饰器
@Aspect
@Component
public class TransactionAspect {
    
    @Around("execution(* com.example.service.*.update*(..) || execution(* com.example.service.*.delete*(..))")
    public Object handleTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        
        System.out.println("🔒 [事务] 开始事务: " + methodName);
        
        try {
            Object result = joinPoint.proceed();
            System.out.println("✅ [事务] 提交事务: " + methodName);
            return result;
        } catch (Exception e) {
            System.out.println("❌ [事务] 回滚事务: " + methodName + ", 原因: " + e.getMessage());
            throw e;
        }
    }
}

// 8. 权限检查装饰器
@Aspect
@Component
public class SecurityAspect {
    
    @Before("execution(* com.example.service.*.delete*(..))")
    public void checkDeletePermission(JoinPoint joinPoint) {
        // 模拟权限检查
        String currentUser = getCurrentUser();
        if (!"admin".equals(currentUser)) {
            throw new SecurityException("用户 " + currentUser + " 无删除权限");
        }
        System.out.println("🔐 [权限] 删除权限检查通过");
    }
    
    @Before("execution(* com.example.service.*.update*(..))")
    public void checkUpdatePermission(JoinPoint joinPoint) {
        String currentUser = getCurrentUser();
        Object[] args = joinPoint.getArgs();
        
        if (args.length > 0 && args[0] instanceof User) {
            User user = (User) args[0];
            if (!currentUser.equals("admin") && !currentUser.equals(user.getName())) {
                throw new SecurityException("用户 " + currentUser + " 无权限修改其他用户信息");
            }
        }
        System.out.println("🔐 [权限] 更新权限检查通过");
    }
    
    private String getCurrentUser() {
        // 模拟获取当前用户
        return "admin"; // 实际应用中从SecurityContext获取
    }
}

// 9. 重试装饰器
@Aspect
@Component
public class RetryAspect {
    
    @Around("execution(* com.example.service.*.get*(..))")
    public Object retry(ProceedingJoinPoint joinPoint) throws Throwable {
        int maxRetries = 3;
        int retryCount = 0;
        
        while (retryCount < maxRetries) {
            try {
                return joinPoint.proceed();
            } catch (Exception e) {
                retryCount++;
                if (retryCount >= maxRetries) {
                    System.out.println("🔄 [重试] 达到最大重试次数,失败");
                    throw e;
                }
                
                System.out.println("🔄 [重试] 第" + retryCount + "次重试...");
                Thread.sleep(1000); // 等待1秒后重试
            }
        }
        
        return null;
    }
}

// 10. 配置类
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    
    @Bean
    public PerformanceMonitoringAspect performanceMonitoringAspect() {
        return new PerformanceMonitoringAspect();
    }
    
    @Bean
    public CacheAspect cacheAspect() {
        return new CacheAspect();
    }
    
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
    
    @Bean
    public TransactionAspect transactionAspect() {
        return new TransactionAspect();
    }
    
    @Bean
    public SecurityAspect securityAspect() {
        return new SecurityAspect();
    }
    
    @Bean
    public RetryAspect retryAspect() {
        return new RetryAspect();
    }
}

// 11. 使用示例
@RestController
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    @PutMapping("/users")
    public void updateUser(@RequestBody User user) {
        userService.updateUser(user);
    }
    
    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}

// 12. 测试类
@SpringBootTest
public class AopDecoratorTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testDecoratorChain() {
        // 测试查询操作(应用:重试 + 缓存 + 性能监控 + 日志)
        System.out.println("=== 测试查询操作 ===");
        User user1 = userService.getUserById(1L);
        User user2 = userService.getUserById(1L); // 第二次查询应该命中缓存
        
        // 测试更新操作(应用:事务 + 权限 + 性能监控 + 日志 + 缓存清理)
        System.out.println("\n=== 测试更新操作 ===");
        userService.updateUser(new User(1L, "UpdatedUser", "updated@example.com"));
        
        // 测试删除操作(应用:事务 + 权限 + 性能监控 + 日志 + 缓存清理)
        System.out.println("\n=== 测试删除操作 ===");
        userService.deleteUser(1L);
    }
}

// 13. 主应用类
@SpringBootApplication
public class AopDecoratorApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopDecoratorApplication.class, args);
    }
}

Servlet过滤器链

查看代码
// 核心接口
public interface Filter {
    void doFilter(ServletRequest request, ServletResponse response, 
                 FilterChain chain) throws IOException, ServletException;
}

// 过滤器链接口
public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response) 
        throws IOException, ServletException;
}

// 装饰器实现:每个Filter都可以看作是对原始请求/响应的装饰器
public class LoggingFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // 前置处理 - 装饰请求
        System.out.println("请求开始: " + ((HttpServletRequest)request).getRequestURI());
        
        // 调用链中的下一个过滤器或目标Servlet
        chain.doFilter(request, response);
        
        // 后置处理 - 装饰响应
        System.out.println("请求结束");
    }
}

// 链式装饰
public class AuthenticationFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // 身份验证装饰
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String token = httpRequest.getHeader("Authorization");
        
        if (isValidToken(token)) {
            // 通过验证,继续链式调用
            chain.doFilter(request, response);
        } else {
            // 验证失败,中断链
            ((HttpServletResponse) response).setStatus(401);
        }
    }
}

// 字符编码过滤器
public class CharacterEncodingFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }
}

// 性能监控过滤器
public class PerformanceFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        long startTime = System.currentTimeMillis();
        
        chain.doFilter(request, response);
        
        long endTime = System.currentTimeMillis();
        System.out.println("请求处理时间: " + (endTime - startTime) + "ms");
    }
}

注意:实际开发中,还需要配置web.xml

查看代码
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>com.example.CharacterEncodingFilter</filter-class>
</filter>
<filter>
    <filter-name>AuthenticationFilter</filter-name>
    <filter-class>com.example.AuthenticationFilter</filter-class>
</filter>
<filter>
    <filter-name>LoggingFilter</filter-name>
    <filter-class>com.example.LoggingFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/api/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>LoggingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Java I/O流(BufferedReader装饰FileReader)

 

posted @ 2020-02-04 22:16  lvlin241  阅读(9)  评论(0)    收藏  举报