设计模式-17策略模式 (Strategy Pattern) 源码实例大全
·
策略模式 (Strategy Pattern) 源码实例大全
模式定义
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
框架源码实例
1. Java Standard Library
Comparator Strategy Pattern
// Java比较器策略模式 - 策略接口
@FunctionalInterface
public interface Comparator<T> {
// 比较两个对象
int compare(T o1, T o2);
// 默认方法 - 反转比较顺序
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
// 默认方法 - 链式比较
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
}
// 具体策略 - 用户年龄比较器
public class UserAgeComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return Integer.compare(u1.getAge(), u2.getAge());
}
}
// 具体策略 - 用户姓名比较器
public class UserNameComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return u1.getName().compareTo(u2.getName());
}
}
// 具体策略 - 用户注册时间比较器
public class UserRegistrationDateComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return u1.getRegistrationDate().compareTo(u2.getRegistrationDate());
}
}
// 具体策略 - 复合比较器
public class UserCompositeComparator implements Comparator<User> {
private final List<Comparator<User>> comparators;
public UserCompositeComparator(List<Comparator<User>> comparators) {
this.comparators = comparators;
}
@Override
public int compare(User u1, User u2) {
for (Comparator<User> comparator : comparators) {
int result = comparator.compare(u1, u2);
if (result != 0) {
return result;
}
}
return 0;
}
}
// 上下文 - 用户服务
public class UserService {
private List<User> users = new ArrayList<>();
private Comparator<User> currentComparator = new UserNameComparator();
public void addUser(User user) {
users.add(user);
}
public void setSortingStrategy(Comparator<User> comparator) {
this.currentComparator = comparator;
}
public List<User> getSortedUsers() {
List<User> sortedUsers = new ArrayList<>(users);
sortedUsers.sort(currentComparator);
return sortedUsers;
}
public List<User> getUsersSortedByAge() {
List<User> sortedUsers = new ArrayList<>(users);
sortedUsers.sort(new UserAgeComparator());
return sortedUsers;
}
public List<User> getUsersSortedByRegistrationDate() {
List<User> sortedUsers = new ArrayList<>(users);
sortedUsers.sort(new UserRegistrationDateComparator());
return sortedUsers;
}
}
ThreadFactory Strategy Pattern
// Java线程工厂策略模式 - 策略接口
public interface ThreadFactory {
// 创建新线程
Thread newThread(Runnable r);
}
// 具体策略 - 默认线程工厂
public class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
// 具体策略 - 守护线程工厂
public class DaemonThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
public DaemonThreadFactory(String namePrefix) {
this.namePrefix = namePrefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, namePrefix + "-" + threadNumber.getAndIncrement());
thread.setDaemon(true);
return thread;
}
}
// 具体策略 - 优先级线程工厂
public class PriorityThreadFactory implements ThreadFactory {
private final int priority;
private final String namePrefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
public PriorityThreadFactory(int priority, String namePrefix) {
this.priority = priority;
this.namePrefix = namePrefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, namePrefix + "-" + threadNumber.getAndIncrement());
thread.setPriority(priority);
return thread;
}
}
// 具体策略 - 异常处理线程工厂
public class ExceptionHandlingThreadFactory implements ThreadFactory {
private final ThreadFactory delegate;
private final Thread.UncaughtExceptionHandler exceptionHandler;
public ExceptionHandlingThreadFactory(ThreadFactory delegate, Thread.UncaughtExceptionHandler exceptionHandler) {
this.delegate = delegate;
this.exceptionHandler = exceptionHandler;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = delegate.newThread(r);
thread.setUncaughtExceptionHandler(exceptionHandler);
return thread;
}
}
// 上下文 - 线程池管理器
public class ThreadPoolManager {
private final ThreadFactory threadFactory;
private final ExecutorService executorService;
public ThreadPoolManager(int poolSize, ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
this.executorService = Executors.newFixedThreadPool(poolSize, threadFactory);
}
public void executeTask(Runnable task) {
executorService.execute(task);
}
public Future<?> submitTask(Runnable task) {
return executorService.submit(task);
}
public <T> Future<T> submitTask(Callable<T> task) {
return executorService.submit(task);
}
public void shutdown() {
executorService.shutdown();
}
}
2. Apache Commons Codec
Encoding Strategy Pattern
// Apache Commons Codec编码策略模式 - 策略接口
public interface Encoder {
// 编码对象
Object encode(Object source) throws EncoderException;
}
// 具体策略 - Base64编码器
public class Base64Encoder implements Encoder {
@Override
public Object encode(Object source) throws EncoderException {
if (!(source instanceof String)) {
throw new EncoderException("Base64Encoder can only encode String objects");
}
return Base64.getEncoder().encodeToString(((String) source).getBytes(StandardCharsets.UTF_8));
}
}
// 具体策略 - URL编码器
public class URLEncoder implements Encoder {
@Override
public Object encode(Object source) throws EncoderException {
if (!(source instanceof String)) {
throw new EncoderException("URLEncoder can only encode String objects");
}
try {
return java.net.URLEncoder.encode((String) source, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new EncoderException("URL encoding failed", e);
}
}
}
// 具体策略 - MD5编码器
public class MD5Encoder implements Encoder {
@Override
public Object encode(Object source) throws EncoderException {
if (!(source instanceof String)) {
throw new EncoderException("MD5Encoder can only encode String objects");
}
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(((String) source).getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new EncoderException("MD5 algorithm not available", e);
}
}
}
// 具体策略 - SHA256编码器
public class SHA256Encoder implements Encoder {
@Override
public Object encode(Object source) throws EncoderException {
if (!(source instanceof String)) {
throw new EncoderException("SHA256Encoder can only encode String objects");
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(((String) source).getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new EncoderException("SHA-256 algorithm not available", e);
}
}
}
// 上下文 - 编码服务
public class EncodingService {
private Encoder currentEncoder = new Base64Encoder();
public void setEncodingStrategy(Encoder encoder) {
this.currentEncoder = encoder;
}
public String encode(String input) throws EncoderException {
return (String) currentEncoder.encode(input);
}
public Map<String, String> encodeWithAllStrategies(String input) throws EncoderException {
Map<String, String> results = new HashMap<>();
results.put("Base64", (String) new Base64Encoder().encode(input));
results.put("URL", (String) new URLEncoder().encode(input));
results.put("MD5", (String) new MD5Encoder().encode(input));
results.put("SHA256", (String) new SHA256Encoder().encode(input));
return results;
}
}
3. Google Guava
Cache Strategy Pattern
// Google Guava缓存策略模式 - 策略接口
public interface CacheLoader<K, V> {
// 加载缓存项
V load(K key) throws Exception;
// 批量加载缓存项
Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception;
}
// 具体策略 - 用户缓存加载器
public class UserCacheLoader extends CacheLoader<Long, User> {
private final UserRepository userRepository;
private final Logger logger = LoggerFactory.getLogger(UserCacheLoader.class);
public UserCacheLoader(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User load(Long userId) throws Exception {
logger.debug("Loading user from database: {}", userId);
User user = userRepository.findById(userId);
if (user == null) {
throw new Exception("User not found: " + userId);
}
return user;
}
@Override
public Map<Long, User> loadAll(Iterable<? extends Long> userIds) throws Exception {
logger.debug("Loading multiple users from database: {}", userIds);
Map<Long, User> users = new HashMap<>();
for (Long userId : userIds) {
users.put(userId, load(userId));
}
return users;
}
}
// 具体策略 - 产品缓存加载器
public class ProductCacheLoader extends CacheLoader<String, Product> {
private final ProductRepository productRepository;
private final Logger logger = LoggerFactory.getLogger(ProductCacheLoader.class);
public ProductCacheLoader(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Override
public Product load(String productCode) throws Exception {
logger.debug("Loading product from database: {}", productCode);
Product product = productRepository.findByCode(productCode);
if (product == null) {
throw new Exception("Product not found: " + productCode);
}
return product;
}
@Override
public Map<String, Product> loadAll(Iterable<? extends String> productCodes) throws Exception {
logger.debug("Loading multiple products from database: {}", productCodes);
Map<String, Product> products = new HashMap<>();
for (String productCode : productCodes) {
products.put(productCode, load(productCode));
}
return products;
}
}
// 具体策略 - 配置缓存加载器
public class ConfigurationCacheLoader extends CacheLoader<String, String> {
private final ConfigurationRepository configurationRepository;
private final Logger logger = LoggerFactory.getLogger(ConfigurationCacheLoader.class);
public ConfigurationCacheLoader(ConfigurationRepository configurationRepository) {
this.configurationRepository = configurationRepository;
}
@Override
public String load(String configKey) throws Exception {
logger.debug("Loading configuration from database: {}", configKey);
String value = configurationRepository.getValue(configKey);
if (value == null) {
throw new Exception("Configuration not found: " + configKey);
}
return value;
}
@Override
public Map<String, String> loadAll(Iterable<? extends String> configKeys) throws Exception {
logger.debug("Loading multiple configurations from database: {}", configKeys);
Map<String, String> configs = new HashMap<>();
for (String configKey : configKeys) {
configs.put(configKey, load(configKey));
}
return configs;
}
}
// 上下文 - 缓存管理器
public class CacheManager<K, V> {
private final Cache<K, V> cache;
private final CacheLoader<K, V> cacheLoader;
public CacheManager(CacheLoader<K, V> cacheLoader, long maximumSize, long expireAfterWrite, TimeUnit timeUnit) {
this.cacheLoader = cacheLoader;
this.cache = CacheBuilder.newBuilder()
.maximumSize(maximumSize)
.expireAfterWrite(expireAfterWrite, timeUnit)
.build(cacheLoader);
}
public V get(K key) throws ExecutionException {
return cache.get(key);
}
public Map<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
return cache.getAll(keys);
}
public void put(K key, V value) {
cache.put(key, value);
}
public void invalidate(K key) {
cache.invalidate(key);
}
public void invalidateAll() {
cache.invalidateAll();
}
public long size() {
return cache.size();
}
public CacheStats stats() {
return cache.stats();
}
}
Rate Limiting Strategy Pattern
// Google Guava限流策略模式 - 策略接口
public interface RateLimiter {
// 获取许可
boolean tryAcquire();
// 获取指定数量的许可
boolean tryAcquire(int permits);
// 阻塞获取许可
void acquire();
// 获取当前速率
double getRate();
}
// 具体策略 - 平滑突发限流器
public class SmoothBurstyRateLimiter implements RateLimiter {
private final com.google.common.util.concurrent.RateLimiter guavaRateLimiter;
private final Logger logger = LoggerFactory.getLogger(SmoothBurstyRateLimiter.class);
public SmoothBurstyRateLimiter(double permitsPerSecond) {
this.guavaRateLimiter = com.google.common.util.concurrent.RateLimiter.create(permitsPerSecond);
logger.info("Created SmoothBurstyRateLimiter with rate: {} permits/second", permitsPerSecond);
}
@Override
public boolean tryAcquire() {
boolean acquired = guavaRateLimiter.tryAcquire();
logger.debug("Try acquire permit: {}", acquired);
return acquired;
}
@Override
public boolean tryAcquire(int permits) {
boolean acquired = guavaRateLimiter.tryAcquire(permits);
logger.debug("Try acquire {} permits: {}", permits, acquired);
return acquired;
}
@Override
public void acquire() {
logger.debug("Blocking acquire permit");
guavaRateLimiter.acquire();
}
@Override
public double getRate() {
return guavaRateLimiter.getRate();
}
}
// 具体策略 - 平滑预热限流器
public class SmoothWarmingUpRateLimiter implements RateLimiter {
private final com.google.common.util.concurrent.RateLimiter guavaRateLimiter;
private final Logger logger = LoggerFactory.getLogger(SmoothWarmingUpRateLimiter.class);
public SmoothWarmingUpRateLimiter(double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
this.guavaRateLimiter = com.google.common.util.concurrent.RateLimiter.create(permitsPerSecond, warmupPeriod, unit);
logger.info("Created SmoothWarmingUpRateLimiter with rate: {} permits/second, warmup: {} {}",
permitsPerSecond, warmupPeriod, unit);
}
@Override
public boolean tryAcquire() {
boolean acquired = guavaRateLimiter.tryAcquire();
logger.debug("Try acquire permit: {}", acquired);
return acquired;
}
@Override
public boolean tryAcquire(int permits) {
boolean acquired = guavaRateLimiter.tryAcquire(permits);
logger.debug("Try acquire {} permits: {}", permits, acquired);
return acquired;
}
@Override
public void acquire() {
logger.debug("Blocking acquire permit");
guavaRateLimiter.acquire();
}
@Override
public double getRate() {
return guavaRateLimiter.getRate();
}
}
// 具体策略 - 令牌桶限流器
public class TokenBucketRateLimiter implements RateLimiter {
private final AtomicInteger tokens;
private final int capacity;
private final double refillRate;
private final ScheduledExecutorService scheduler;
private final Logger logger = LoggerFactory.getLogger(TokenBucketRateLimiter.class);
public TokenBucketRateLimiter(int capacity, double refillRatePerSecond) {
this.capacity = capacity;
this.tokens = new AtomicInteger(capacity);
this.refillRate = refillRatePerSecond;
this.scheduler = Executors.newSingleThreadScheduledExecutor();
// 定期补充令牌
long refillInterval = (long) (1000 / refillRatePerSecond);
scheduler.scheduleAtFixedRate(this::refillTokens, refillInterval, refillInterval, TimeUnit.MILLISECONDS);
logger.info("Created TokenBucketRateLimiter with capacity: {}, refill rate: {} tokens/second",
capacity, refillRatePerSecond);
}
private void refillTokens() {
int currentTokens = tokens.get();
int newTokens = Math.min(capacity, currentTokens + 1);
if (tokens.compareAndSet(currentTokens, newTokens)) {
logger.debug("Refilled token, current tokens: {}", newTokens);
}
}
@Override
public boolean tryAcquire() {
return tryAcquire(1);
}
@Override
public boolean tryAcquire(int permits) {
while (true) {
int current = tokens.get();
if (current < permits) {
logger.debug("Not enough tokens, current: {}, requested: {}", current, permits);
return false;
}
if (tokens.compareAndSet(current, current - permits)) {
logger.debug("Acquired {} tokens, remaining: {}", permits, current - permits);
return true;
}
}
}
@Override
public void acquire() {
while (!tryAcquire()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Interrupted while waiting for tokens", e);
}
}
}
@Override
public double getRate() {
return refillRate;
}
public void shutdown() {
scheduler.shutdown();
}
}
// 上下文 - API限流器
public class ApiRateLimiter {
private final Map<String, RateLimiter> endpointLimiters = new ConcurrentHashMap<>();
private final RateLimiter defaultLimiter;
public ApiRateLimiter(double defaultRate) {
this.defaultLimiter = new SmoothBurstyRateLimiter(defaultRate);
}
public void addEndpointLimiter(String endpoint, RateLimiter limiter) {
endpointLimiters.put(endpoint, limiter);
}
public boolean tryAcquire(String endpoint) {
RateLimiter limiter = endpointLimiters.getOrDefault(endpoint, defaultLimiter);
return limiter.tryAcquire();
}
public boolean tryAcquire(String endpoint, int permits) {
RateLimiter limiter = endpointLimiters.getOrDefault(endpoint, defaultLimiter);
return limiter.tryAcquire(permits);
}
public void acquire(String endpoint) {
RateLimiter limiter = endpointLimiters.getOrDefault(endpoint, defaultLimiter);
limiter.acquire();
}
public double getRate(String endpoint) {
RateLimiter limiter = endpointLimiters.getOrDefault(endpoint, defaultLimiter);
return limiter.getRate();
}
}
4. Apache HttpClient
Redirect Strategy Pattern
// Apache HttpClient重定向策略模式 - 策略接口
public interface RedirectStrategy {
// 判断是否自动重定向
boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException;
// 获取重定向位置
HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException;
}
// 具体策略 - 默认重定向策略
public class DefaultRedirectStrategy implements RedirectStrategy {
private final Logger logger = LoggerFactory.getLogger(DefaultRedirectStrategy.class);
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");
int statusCode = response.getStatusLine().getStatusCode();
String method = request.getRequestLine().getMethod();
Header locationHeader = response.getFirstHeader("location");
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_TEMPORARY_REDIRECT:
return isRedirectable(method) && locationHeader != null;
case HttpStatus.SC_SEE_OTHER:
return locationHeader != null;
default:
return false;
}
}
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
URI location = createLocationURI(response.getFirstHeader("location").getValue());
String method = request.getRequestLine().getMethod();
if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
return new HttpHead(location);
} else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {
return new HttpGet(location);
} else {
int status = response.getStatusLine().getStatusCode();
if (status == HttpStatus.SC_TEMPORARY_REDIRECT || status == HttpStatus.SC_SEE_OTHER) {
return new HttpGet(location);
} else {
return RequestBuilder.copy(request).setUri(location).build();
}
}
}
protected boolean isRedirectable(String method) {
return Arrays.binarySearch(new String[]{
HttpGet.METHOD_NAME,
HttpHead.METHOD_NAME,
HttpPost.METHOD_NAME,
HttpPut.METHOD_NAME,
HttpDelete.METHOD_NAME
}, method) >= 0;
}
protected URI createLocationURI(String location) throws ProtocolException {
try {
return new URI(location);
} catch (URISyntaxException ex) {
throw new ProtocolException("Invalid redirect URI: " + location, ex);
}
}
}
// 具体策略 - 宽松重定向策略
public class LaxRedirectStrategy extends DefaultRedirectStrategy {
private final Logger logger = LoggerFactory.getLogger(LaxRedirectStrategy.class);
@Override
protected boolean isRedirectable(String method) {
return true; // 允许所有HTTP方法重定向
}
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
logger.info("Using lax redirect strategy");
return super.getRedirect(request, response, context);
}
}
// 具体策略 - 严格重定向策略
public class StrictRedirectStrategy implements RedirectStrategy {
private final Logger logger = LoggerFactory.getLogger(StrictRedirectStrategy.class);
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");
int statusCode = response.getStatusLine().getStatusCode();
String method = request.getRequestLine().getMethod();
Header locationHeader = response.getFirstHeader("location");
// 只允许GET和HEAD方法重定向
boolean isGetOrHead = HttpGet.METHOD_NAME.equalsIgnoreCase(method) || HttpHead.METHOD_NAME.equalsIgnoreCase(method);
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_TEMPORARY_REDIRECT:
case HttpStatus.SC_SEE_OTHER:
return isGetOrHead && locationHeader != null;
default:
return false;
}
}
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
logger.info("Using strict redirect strategy");
URI location = createLocationURI(response.getFirstHeader("location").getValue());
String method = request.getRequestLine().getMethod();
if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
return new HttpHead(location);
} else {
return new HttpGet(location);
}
}
protected URI createLocationURI(String location) throws ProtocolException {
try {
return new URI(location);
} catch (URISyntaxException ex) {
throw new ProtocolException("Invalid redirect URI: " + location, ex);
}
}
}
// 具体策略 - 自定义重定向策略
public class CustomRedirectStrategy implements RedirectStrategy {
private final int maxRedirects;
private final Set<Integer> allowedStatusCodes;
private final Logger logger = LoggerFactory.getLogger(CustomRedirectStrategy.class);
public CustomRedirectStrategy(int maxRedirects, Set<Integer> allowedStatusCodes) {
this.maxRedirects = maxRedirects;
this.allowedStatusCodes = allowedStatusCodes;
}
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
int statusCode = response.getStatusLine().getStatusCode();
Header locationHeader = response.getFirstHeader("location");
// 检查重定向次数
RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(HttpClientContext.REDIRECT_LOCATIONS);
if (redirectLocations != null && redirectLocations.size() >= maxRedirects) {
logger.warn("Maximum redirects reached: {}", maxRedirects);
return false;
}
boolean isAllowedStatus = allowedStatusCodes.contains(statusCode);
boolean hasLocation = locationHeader != null;
logger.debug("Redirect check - status: {}, allowed: {}, hasLocation: {}",
statusCode, isAllowedStatus, hasLocation);
return isAllowedStatus && hasLocation;
}
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
logger.info("Getting redirect for custom strategy");
URI location = createLocationURI(response.getFirstHeader("location").getValue());
return new HttpGet(location);
}
protected URI createLocationURI(String location) throws ProtocolException {
try {
return new URI(location);
} catch (URISyntaxException ex) {
throw new ProtocolException("Invalid redirect URI: " + location, ex);
}
}
}
// 上下文 - HTTP客户端
public class HttpClientWithRedirect {
private final CloseableHttpClient httpClient;
private RedirectStrategy redirectStrategy;
public HttpClientWithRedirect(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
this.httpClient = HttpClients.custom()
.setRedirectStrategy(redirectStrategy)
.build();
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
// 重新创建HTTP客户端
try {
httpClient.close();
} catch (IOException e) {
// 记录日志
}
// 重新创建HTTP客户端的逻辑
}
public CloseableHttpResponse execute(HttpUriRequest request) throws IOException {
return httpClient.execute(request);
}
public String getRedirectStrategyName() {
return redirectStrategy.getClass().getSimpleName();
}
}
5. Netflix Ribbon
Load Balancing Strategy Pattern
// Netflix Ribbon负载均衡策略模式 - 策略接口
public interface IRule {
// 选择服务器
Server choose(Object key);
// 设置负载均衡器
void setLoadBalancer(ILoadBalancer lb);
// 获取负载均衡器
ILoadBalancer getLoadBalancer();
}
// 具体策略 - 轮询策略
public class RoundRobinRule extends AbstractLoadBalancerRule {
private final AtomicInteger nextServerCyclicCounter;
private final Logger logger = LoggerFactory.getLogger(RoundRobinRule.class);
public RoundRobinRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
@Override
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
logger.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
logger.warn("No up servers available from load balancer: " + lb);
return null;
}
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return server;
}
server = null;
}
if (count >= 10) {
logger.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next)) {
return next;
}
}
}
}
// 具体策略 - 随机策略
public class RandomRule extends AbstractLoadBalancerRule {
private final Random rand;
private final Logger logger = LoggerFactory.getLogger(RandomRule.class);
public RandomRule() {
rand = new Random();
}
@Override
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
int index = rand.nextInt(serverCount);
server = allList.get(index);
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
return server;
}
}
// 具体策略 - 加权响应时间策略
public class WeightedResponseTimeRule extends RoundRobinRule {
public static final IClientConfigKey<Integer> WEIGHT_TASK_TIMER_INTERVAL_CONFIG_KEY = new IClientConfigKey<Integer>() {
@Override
public String key() {
return "WeightedResponseTimeRuleTimerInterval";
}
@Override
public String toString() {
return key();
}
@Override
public Class<Integer> type() {
return Integer.class;
}
};
public static final int DEFAULT_TIMER_INTERVAL = 30 * 1000;
private int serverWeightTaskTimerInterval = DEFAULT_TIMER_INTERVAL;
private static final double DEFAULT_WEIGHT = 1.0D;
private volatile List<Double> accumulatedWeights = new ArrayList<Double>();
private final Random random = new Random();
protected Timer serverWeightTimer = null;
protected AtomicBoolean serverWeightAssignmentInProgress = new AtomicBoolean(false);
private final Logger logger = LoggerFactory.getLogger(WeightedResponseTimeRule.class);
@Override
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
if (lb instanceof BaseLoadBalancer) {
name = ((BaseLoadBalancer) lb).getName();
}
initialize(lb);
}
void initialize(ILoadBalancer lb) {
if (serverWeightTimer != null) {
serverWeightTimer.cancel();
}
serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-" + name, true);
serverWeightTimer.schedule(new DynamicServerWeightTask(), 0, serverWeightTaskTimerInterval);
ServerWeight sw = new ServerWeight();
sw.maintainWeights();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
logger.info("Stopping NFLoadBalancer-serverWeightTimer-" + name);
serverWeightTimer.cancel();
}
}));
}
@Override
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
List<Double> currentWeights = accumulatedWeights;
if (Thread.interrupted()) {
return null;
}
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
int serverIndex = 0;
List<Server> reachableServers = lb.getReachableServers();
if (currentWeights != null && currentWeights.size() == serverCount) {
serverIndex = randomWithWeight(currentWeights);
server = allList.get(serverIndex);
} else {
server = super.choose(lb, key);
}
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return server;
}
server = null;
}
return server;
}
private int randomWithWeight(List<Double> currentWeights) {
double randomWeight = random.nextDouble();
int serverIndex = 0;
for (Double weight : currentWeights) {
if (randomWeight < weight) {
return serverIndex;
}
serverIndex++;
}
return serverIndex - 1;
}
}
// 具体策略 - 可用性过滤策略
public class AvailabilityFilteringRule extends ClientConfigEnabledRoundRobinRule {
private AbstractServerPredicate predicate;
public AvailabilityFilteringRule() {
super();
predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, null))
.addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
.build();
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, clientConfig))
.addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
.build();
}
@Override
public Server choose(Object key) {
int count = 0;
Server server = roundRobinRule.choose(key);
while (count++ <= 10) {
if (predicate.apply(new PredicateKey(server))) {
return server;
}
server = roundRobinRule.choose(key);
}
return super.choose(key);
}
}
// 上下文 - 负载均衡器
public class LoadBalancer {
private final ILoadBalancer loadBalancer;
private IRule loadBalancingRule;
public LoadBalancer(List<Server> servers, IRule loadBalancingRule) {
this.loadBalancingRule = loadBalancingRule;
this.loadBalancer = new BaseLoadBalancer();
for (Server server : servers) {
loadBalancer.addServer(server);
}
loadBalancingRule.setLoadBalancer(loadBalancer);
}
public void setLoadBalancingRule(IRule loadBalancingRule) {
this.loadBalancingRule = loadBalancingRule;
this.loadBalancingRule.setLoadBalancer(loadBalancer);
}
public Server chooseServer(Object key) {
return loadBalancingRule.choose(key);
}
public String getCurrentStrategyName() {
return loadBalancingRule.getClass().getSimpleName();
}
public List<Server> getAllServers() {
return loadBalancer.getAllServers();
}
public List<Server> getReachableServers() {
return loadBalancer.getReachableServers();
}
}
6. Apache Log4j
Appender Strategy Pattern
// Apache Log4j附加器策略模式 - 策略接口
public interface Appender {
// 追加日志事件
void append(LogEvent event);
// 获取附加器名称
String getName();
// 设置附加器名称
void setName(String name);
// 忽略异常
boolean ignoreExceptions();
// 获取错误处理器
ErrorHandler getHandler();
// 设置错误处理器
void setHandler(ErrorHandler handler);
// 获取布局
Layout<? extends Serializable> getLayout();
// 设置布局
void setLayout(Layout<? extends Serializable> layout);
}
// 具体策略 - 控制台附加器
public class ConsoleAppender extends AbstractOutputStreamAppender<ConsoleManager> {
private static final Logger LOGGER = StatusLogger.getLogger();
public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
implements org.apache.logging.log4j.core.util.Builder<ConsoleAppender> {
@Override
public ConsoleAppender build() {
final Layout<? extends Serializable> layout = getLayout();
if (layout == null) {
AbstractLifeCycle.LOGGER.error("No layout provided for ConsoleAppender");
return null;
}
final ConsoleManager manager = ConsoleManager.getManager(getName(), getTarget(), getFollow(), layout);
if (manager == null) {
return null;
}
return new ConsoleAppender(getName(), layout, getFilter(), manager, isIgnoreExceptions(), getPropertyArray());
}
}
public enum Target {
SYSTEM_OUT,
SYSTEM_ERR
}
private ConsoleAppender(String name, Layout<? extends Serializable> layout, Filter filter, ConsoleManager manager, boolean ignoreExceptions, Property[] properties) {
super(name, layout, filter, ignoreExceptions, true, manager, properties);
}
@Override
public void append(LogEvent event) {
getManager().write(event);
}
}
// 具体策略 - 文件附加器
public class FileAppender extends AbstractOutputStreamAppender<FileManager> {
private static final long serialVersionUID = 1L;
public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
implements org.apache.logging.log4j.core.util.Builder<FileAppender> {
@PluginBuilderAttribute
@Required(message = "No file name provided")
private String fileName;
@PluginBuilderAttribute
private boolean append = true;
@PluginBuilderAttribute
private boolean locking;
@PluginBuilderAttribute
private boolean advertise;
@PluginBuilderAttribute
private String advertiseUri;
@PluginBuilderAttribute
private boolean createOnDemand;
@Override
public FileAppender build() {
final Layout<? extends Serializable> layout = getLayout();
final String name = getName();
final FileManager manager = FileManager.getFileManager(fileName, append, locking, advertiseUri, layout, bufferSize, isImmediateFlush(), createOnDemand, getConfiguration());
if (manager == null) {
return null;
}
return new FileAppender(name, layout, getFilter(), manager, fileName, isIgnoreExceptions(), isImmediateFlush(), advertise ? getConfiguration().getAdvertiser() : null, getPropertyArray());
}
}
private FileAppender(String name, Layout<? extends Serializable> layout, Filter filter, FileManager manager, String fileName, boolean ignoreExceptions, boolean immediateFlush, Advertiser advertiser, Property[] properties) {
super(name, layout, filter, ignoreExceptions, immediateFlush, manager, properties);
}
@Override
public void append(LogEvent event) {
getManager().write(event);
}
}
// 具体策略 - 数据库附加器
public class JdbcAppender extends AbstractDatabaseAppender<JdbcDatabaseManager> {
private final String description = "JdbcAppender";
public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
implements org.apache.logging.log4j.core.util.Builder<JdbcAppender> {
@PluginBuilderAttribute
@Required(message = "No connection source provided")
private ConnectionSource connectionSource;
@PluginBuilderAttribute
@Required(message = "No SQL statement provided")
private String sqlStatement;
@Override
public JdbcAppender build() {
final String name = getName();
final JdbcDatabaseManager manager = JdbcDatabaseManager.getJdbcDatabaseManager(name, getBufferSize(), connectionSource, sqlStatement, isImmediateFail());
return new JdbcAppender(name, getFilter(), getLayout(), isIgnoreExceptions(), manager);
}
}
private JdbcAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, JdbcDatabaseManager manager) {
super(name, filter, layout, ignoreExceptions, manager);
}
@Override
public void append(LogEvent event) {
getManager().writeEvent(event, this);
}
}
// 具体策略 - 网络附加器
public class SocketAppender extends AbstractOutputStreamAppender<SocketManager> {
public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
implements org.apache.logging.log4j.core.util.Builder<SocketAppender> {
@PluginBuilderAttribute
private boolean immediateFail = true;
@PluginBuilderAttribute
@Required(message = "No host name provided")
private String host;
@PluginBuilderAttribute
@Required(message = "No port number provided")
private int port;
@PluginBuilderAttribute
private int connectTimeoutMillis = 0;
@PluginBuilderAttribute
private int reconnectionDelayMillis = 0;
@Override
public SocketAppender build() {
final Layout<? extends Serializable> layout = getLayout();
if (layout == null) {
AbstractLifeCycle.LOGGER.error("No layout provided for SocketAppender");
return null;
}
final SocketManager manager = SocketManager.getSocketManager(getName(), layout, host, port, connectTimeoutMillis, reconnectionDelayMillis, immediateFail, getPropertyArray());
if (manager == null) {
return null;
}
return new SocketAppender(getName(), layout, getFilter(), manager, isIgnoreExceptions(), getPropertyArray());
}
}
private SocketAppender(String name, Layout<? extends Serializable> layout, Filter filter, SocketManager manager, boolean ignoreExceptions, Property[] properties) {
super(name, layout, filter, ignoreExceptions, true, manager, properties);
}
@Override
public void append(LogEvent event) {
getManager().write(event);
}
}
// 上下文 - 日志管理器
public class LoggingManager {
private final Map<String, Appender> appenders = new HashMap<>();
private Appender currentAppender;
public LoggingManager() {
// 初始化默认附加器
ConsoleAppender consoleAppender = ConsoleAppender.newBuilder()
.setName("Console")
.setLayout(PatternLayout.newBuilder().withPattern("%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n").build())
.build();
appenders.put("console", consoleAppender);
currentAppender = consoleAppender;
}
public void addAppender(String name, Appender appender) {
appenders.put(name, appender);
}
public void setAppender(String name) {
Appender appender = appenders.get(name);
if (appender != null) {
currentAppender = appender;
}
}
public void log(LogEvent event) {
currentAppender.append(event);
}
public void log(String level, String message) {
LogEvent event = Log4jLogEvent.newBuilder()
.setLevel(Level.getLevel(level))
.setMessage(new SimpleMessage(message))
.setTimeMillis(System.currentTimeMillis())
.build();
log(event);
}
public String getCurrentAppenderName() {
return currentAppender.getName();
}
public Set<String> getAvailableAppenders() {
return appenders.keySet();
}
}
7. Spring Framework
Spring Validation Strategy Pattern
// Spring验证策略模式 - 验证策略接口
public interface Validator {
// 验证对象
boolean supports(Class<?> clazz);
// 执行验证
void validate(Object target, Errors errors);
}
// 具体策略 - 用户验证器
public class UserValidator implements Validator {
private final Logger logger = LoggerFactory.getLogger(UserValidator.class);
@Override
public boolean supports(Class<?> clazz) {
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
logger.info("Validating user object");
User user = (User) target;
// 验证用户名
if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
errors.rejectValue("username", "username.empty", "Username is required");
} else if (user.getUsername().length() < 3) {
errors.rejectValue("username", "username.short", "Username must be at least 3 characters");
} else if (user.getUsername().length() > 20) {
errors.rejectValue("username", "username.long", "Username must be less than 20 characters");
}
// 验证邮箱
if (user.getEmail() == null || user.getEmail().trim().isEmpty()) {
errors.rejectValue("email", "email.empty", "Email is required");
} else if (!isValidEmail(user.getEmail())) {
errors.rejectValue("email", "email.invalid", "Email format is invalid");
}
// 验证年龄
if (user.getAge() == null) {
errors.rejectValue("age", "age.empty", "Age is required");
} else if (user.getAge() < 18) {
errors.rejectValue("age", "age.min", "Age must be at least 18");
} else if (user.getAge() > 120) {
errors.rejectValue("age", "age.max", "Age must be less than 120");
}
logger.info("User validation completed, errors: {}", errors.getErrorCount());
}
private boolean isValidEmail(String email) {
String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
return email.matches(emailRegex);
}
}
// 具体策略 - 产品验证器
public class ProductValidator implements Validator {
private final Logger logger = LoggerFactory.getLogger(ProductValidator.class);
@Override
public boolean supports(Class<?> clazz) {
return Product.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
logger.info("Validating product object");
Product product = (Product) target;
// 验证产品名称
if (product.getName() == null || product.getName().trim().isEmpty()) {
errors.rejectValue("name", "name.empty", "Product name is required");
} else if (product.getName().length() < 2) {
errors.rejectValue("name", "name.short", "Product name must be at least 2 characters");
}
// 验证价格
if (product.getPrice() == null) {
errors.rejectValue("price", "price.empty", "Price is required");
} else if (product.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
errors.rejectValue("price", "price.negative", "Price must be greater than zero");
} else if (product.getPrice().compareTo(new BigDecimal("10000")) > 0) {
errors.rejectValue("price", "price.max", "Price must be less than 10000");
}
// 验证库存
if (product.getStock() == null) {
errors.rejectValue("stock", "stock.empty", "Stock is required");
} else if (product.getStock() < 0) {
errors.rejectValue("stock", "stock.negative", "Stock cannot be negative");
}
logger.info("Product validation completed, errors: {}", errors.getErrorCount());
}
}
// 具体策略 - 订单验证器
public class OrderValidator implements Validator {
private final Logger logger = LoggerFactory.getLogger(OrderValidator.class);
@Override
public boolean supports(Class<?> clazz) {
return Order.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
logger.info("Validating order object");
Order order = (Order) target;
// 验证订单项
if (order.getItems() == null || order.getItems().isEmpty()) {
errors.rejectValue("items", "items.empty", "Order must contain at least one item");
} else {
for (int i = 0; i < order.getItems().size(); i++) {
OrderItem item = order.getItems().get(i);
if (item.getQuantity() <= 0) {
errors.rejectValue("items[" + i + "].quantity", "quantity.invalid", "Quantity must be greater than zero");
}
}
}
// 验证总金额
if (order.getTotalAmount() == null) {
errors.rejectValue("totalAmount", "totalAmount.empty", "Total amount is required");
} else if (order.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0) {
errors.rejectValue("totalAmount", "totalAmount.invalid", "Total amount must be greater than zero");
}
// 验证客户信息
if (order.getCustomerId() == null) {
errors.rejectValue("customerId", "customerId.empty", "Customer ID is required");
}
logger.info("Order validation completed, errors: {}", errors.getErrorCount());
}
}
// 上下文 - 验证服务
public class ValidationService {
private final Map<Class<?>, Validator> validators = new HashMap<>();
private final Logger logger = LoggerFactory.getLogger(ValidationService.class);
public ValidationService() {
// 注册验证器
validators.put(User.class, new UserValidator());
validators.put(Product.class, new ProductValidator());
validators.put(Order.class, new OrderValidator());
}
public void addValidator(Class<?> clazz, Validator validator) {
validators.put(clazz, validator);
}
public <T> ValidationResult validate(T object) {
logger.info("Starting validation for object: {}", object.getClass().getSimpleName());
Validator validator = validators.get(object.getClass());
if (validator == null) {
logger.warn("No validator found for class: {}", object.getClass().getName());
return new ValidationResult(false, "No validator found for this object type");
}
if (!validator.supports(object.getClass())) {
logger.warn("Validator does not support class: {}", object.getClass().getName());
return new ValidationResult(false, "Validator does not support this object type");
}
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(object, object.getClass().getSimpleName());
validator.validate(object, errors);
if (errors.hasErrors()) {
List<String> errorMessages = new ArrayList<>();
for (ObjectError error : errors.getAllErrors()) {
errorMessages.add(error.getDefaultMessage());
}
logger.warn("Validation failed with {} errors", errorMessages.size());
return new ValidationResult(false, String.join("; ", errorMessages));
}
logger.info("Validation completed successfully");
return new ValidationResult(true, "Validation passed");
}
public <T> ValidationResult validateWithStrategy(Class<? extends Validator> validatorClass, T object) {
try {
Validator validator = validatorClass.getDeclaredConstructor().newInstance();
if (validator.supports(object.getClass())) {
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(object, object.getClass().getSimpleName());
validator.validate(object, errors);
if (errors.hasErrors()) {
List<String> errorMessages = new ArrayList<>();
for (ObjectError error : errors.getAllErrors()) {
errorMessages.add(error.getDefaultMessage());
}
return new ValidationResult(false, String.join("; ", errorMessages));
}
return new ValidationResult(true, "Validation passed");
}
} catch (Exception e) {
logger.error("Error creating validator", e);
}
return new ValidationResult(false, "Validator creation failed");
}
}
Spring MessageConverter Strategy Pattern
// Spring消息转换策略模式 - 消息转换策略接口
public interface MessageConverter {
// 转换消息
Object fromMessage(Message message) throws MessageConversionException;
// 转换对象到消息
Message toMessage(Object object, Session session) throws JMSException, MessageConversionException;
}
// 具体策略 - JSON消息转换器
public class JsonMessageConverter implements MessageConverter {
private final ObjectMapper objectMapper = new ObjectMapper();
private final Logger logger = LoggerFactory.getLogger(JsonMessageConverter.class);
@Override
public Object fromMessage(Message message) throws MessageConversionException {
try {
if (message instanceof TextMessage) {
String json = ((TextMessage) message).getText();
logger.debug("Converting JSON message: {}", json);
return objectMapper.readValue(json, Map.class);
} else {
throw new MessageConversionException("Message must be TextMessage for JSON conversion");
}
} catch (Exception e) {
logger.error("Error converting from JSON message", e);
throw new MessageConversionException("Failed to convert JSON message", e);
}
}
@Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
try {
logger.debug("Converting object to JSON message: {}", object);
String json = objectMapper.writeValueAsString(object);
TextMessage message = session.createTextMessage(json);
logger.info("Object converted to JSON message successfully");
return message;
} catch (Exception e) {
logger.error("Error converting object to JSON message", e);
throw new MessageConversionException("Failed to convert object to JSON message", e);
}
}
}
// 具体策略 - XML消息转换器
public class XmlMessageConverter implements MessageConverter {
private final JAXBContext jaxbContext;
private final Logger logger = LoggerFactory.getLogger(XmlMessageConverter.class);
public XmlMessageConverter(Class<?>... classesToBeBound) throws JAXBException {
this.jaxbContext = JAXBContext.newInstance(classesToBeBound);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
try {
if (message instanceof TextMessage) {
String xml = ((TextMessage) message).getText();
logger.debug("Converting XML message: {}", xml);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
return unmarshaller.unmarshal(new StringReader(xml));
} else {
throw new MessageConversionException("Message must be TextMessage for XML conversion");
}
} catch (Exception e) {
logger.error("Error converting from XML message", e);
throw new MessageConversionException("Failed to convert XML message", e);
}
}
@Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
try {
logger.debug("Converting object to XML message: {}", object);
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(object, writer);
TextMessage message = session.createTextMessage(writer.toString());
logger.info("Object converted to XML message successfully");
return message;
} catch (Exception e) {
logger.error("Error converting object to XML message", e);
throw new MessageConversionException("Failed to convert object to XML message", e);
}
}
}
// 具体策略 - 字节数组消息转换器
public class BytesMessageConverter implements MessageConverter {
private final Logger logger = LoggerFactory.getLogger(BytesMessageConverter.class);
@Override
public Object fromMessage(Message message) throws MessageConversionException {
try {
if (message instanceof BytesMessage) {
BytesMessage bytesMessage = (BytesMessage) message;
byte[] bytes = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(bytes);
logger.debug("Converting bytes message, length: {}", bytes.length);
return bytes;
} else {
throw new MessageConversionException("Message must be BytesMessage for byte array conversion");
}
} catch (Exception e) {
logger.error("Error converting from bytes message", e);
throw new MessageConversionException("Failed to convert bytes message", e);
}
}
@Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
try {
if (object instanceof byte[]) {
byte[] bytes = (byte[]) object;
logger.debug("Converting byte array to message, length: {}", bytes.length);
BytesMessage message = session.createBytesMessage();
message.writeBytes(bytes);
logger.info("Byte array converted to message successfully");
return message;
} else {
throw new MessageConversionException("Object must be byte array for BytesMessage conversion");
}
} catch (Exception e) {
logger.error("Error converting byte array to message", e);
throw new MessageConversionException("Failed to convert byte array to message", e);
}
}
}
// 具体策略 - 对象序列化消息转换器
public class SerializableMessageConverter implements MessageConverter {
private final Logger logger = LoggerFactory.getLogger(SerializableMessageConverter.class);
@Override
public Object fromMessage(Message message) throws MessageConversionException {
try {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
Serializable object = objectMessage.getObject();
logger.debug("Converting object message: {}", object);
return object;
} else {
throw new MessageConversionException("Message must be ObjectMessage for Serializable conversion");
}
} catch (Exception e) {
logger.error("Error converting from object message", e);
throw new MessageConversionException("Failed to convert object message", e);
}
}
@Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
try {
if (object instanceof Serializable) {
logger.debug("Converting Serializable object to message: {}", object);
ObjectMessage message = session.createObjectMessage((Serializable) object);
logger.info("Serializable object converted to message successfully");
return message;
} else {
throw new MessageConversionException("Object must implement Serializable");
}
} catch (Exception e) {
logger.error("Error converting Serializable object to message", e);
throw new MessageConversionException("Failed to convert Serializable object to message", e);
}
}
}
// 上下文 - 消息转换服务
public class MessageConversionService {
private final Map<String, MessageConverter> converters = new HashMap<>();
private MessageConverter defaultConverter;
private final Logger logger = LoggerFactory.getLogger(MessageConversionService.class);
public MessageConversionService() {
// 注册默认转换器
try {
converters.put("json", new JsonMessageConverter());
converters.put("xml", new XmlMessageConverter(User.class, Product.class, Order.class));
converters.put("bytes", new BytesMessageConverter());
converters.put("serializable", new SerializableMessageConverter());
defaultConverter = converters.get("json");
} catch (Exception e) {
logger.error("Error initializing default converters", e);
}
}
public void addConverter(String name, MessageConverter converter) {
converters.put(name, converter);
}
public void setDefaultConverter(String name) {
MessageConverter converter = converters.get(name);
if (converter != null) {
defaultConverter = converter;
}
}
public Message toMessage(Object object, Session session) throws JMSException {
return toMessage(object, session, null);
}
public Message toMessage(Object object, Session session, String converterName) throws JMSException {
MessageConverter converter = converterName != null ? converters.get(converterName) : defaultConverter;
if (converter == null) {
throw new JMSException("No converter found for name: " + converterName);
}
logger.info("Converting object to message using converter: {}", converter.getClass().getSimpleName());
return converter.toMessage(object, session);
}
public Object fromMessage(Message message) throws JMSException {
return fromMessage(message, null);
}
public Object fromMessage(Message message, String converterName) throws JMSException {
MessageConverter converter = converterName != null ? converters.get(converterName) : defaultConverter;
if (converter == null) {
throw new JMSException("No converter found for name: " + converterName);
}
logger.info("Converting message to object using converter: {}", converter.getClass().getSimpleName());
return converter.fromMessage(message);
}
public List<String> getAvailableConverters() {
return new ArrayList<>(converters.keySet());
}
}
8. Apache Kafka
Kafka Serialization Strategy Pattern
// Kafka序列化策略模式 - 序列化策略接口
public interface Serializer<T> {
// 配置序列化器
void configure(Map<String, ?> configs, boolean isKey);
// 序列化对象
byte[] serialize(String topic, T data);
// 关闭序列化器
void close();
}
// 具体策略 - JSON序列化器
public class JsonSerializer<T> implements Serializer<T> {
private final ObjectMapper objectMapper = new ObjectMapper();
private final Logger logger = LoggerFactory.getLogger(JsonSerializer.class);
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
logger.info("Configuring JSON serializer, isKey: {}", isKey);
// 可以在这里配置ObjectMapper
}
@Override
public byte[] serialize(String topic, T data) {
if (data == null) {
return null;
}
try {
logger.debug("Serializing object to JSON for topic: {}", topic);
String json = objectMapper.writeValueAsString(data);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
logger.debug("Object serialized to JSON successfully, length: {}", bytes.length);
return bytes;
} catch (Exception e) {
logger.error("Error serializing object to JSON", e);
throw new SerializationException("Failed to serialize object to JSON", e);
}
}
@Override
public void close() {
logger.info("Closing JSON serializer");
}
}
// 具体策略 - Avro序列化器
public class AvroSerializer<T> implements Serializer<T> {
private final Schema schema;
private final DatumWriter<T> datumWriter;
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private final BinaryEncoder encoder;
private final Logger logger = LoggerFactory.getLogger(AvroSerializer.class);
public AvroSerializer(Schema schema) {
this.schema = schema;
this.datumWriter = new ReflectDatumWriter<>(schema);
this.encoder = EncoderFactory.get().binaryEncoder(outputStream, null);
}
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
logger.info("Configuring Avro serializer, isKey: {}", isKey);
}
@Override
public byte[] serialize(String topic, T data) {
if (data == null) {
return null;
}
try {
logger.debug("Serializing object to Avro for topic: {}", topic);
outputStream.reset();
datumWriter.write(data, encoder);
encoder.flush();
byte[] bytes = outputStream.toByteArray();
logger.debug("Object serialized to Avro successfully, length: {}", bytes.length);
return bytes;
} catch (Exception e) {
logger.error("Error serializing object to Avro", e);
throw new SerializationException("Failed to serialize object to Avro", e);
}
}
@Override
public void close() {
logger.info("Closing Avro serializer");
try {
outputStream.close();
} catch (IOException e) {
logger.error("Error closing output stream", e);
}
}
}
// 具体策略 - Protobuf序列化器
public class ProtobufSerializer<T extends Message> implements Serializer<T> {
private final Logger logger = LoggerFactory.getLogger(ProtobufSerializer.class);
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
logger.info("Configuring Protobuf serializer, isKey: {}", isKey);
}
@Override
public byte[] serialize(String topic, T data) {
if (data == null) {
return null;
}
try {
logger.debug("Serializing object to Protobuf for topic: {}", topic);
byte[] bytes = data.toByteArray();
logger.debug("Object serialized to Protobuf successfully, length: {}", bytes.length);
return bytes;
} catch (Exception e) {
logger.error("Error serializing object to Protobuf", e);
throw new SerializationException("Failed to serialize object to Protobuf", e);
}
}
@Override
public void close() {
logger.info("Closing Protobuf serializer");
}
}
// 具体策略 - Kryo序列化器
public class KryoSerializer<T> implements Serializer<T> {
private final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
return kryo;
});
private final ThreadLocal<Output> outputThreadLocal = ThreadLocal.withInitial(() -> new Output(1024, -1));
private final Logger logger = LoggerFactory.getLogger(KryoSerializer.class);
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
logger.info("Configuring Kryo serializer, isKey: {}", isKey);
}
@Override
public byte[] serialize(String topic, T data) {
if (data == null) {
return null;
}
try {
logger.debug("Serializing object to Kryo for topic: {}", topic);
Kryo kryo = kryoThreadLocal.get();
Output output = outputThreadLocal.get();
output.clear();
kryo.writeClassAndObject(output, data);
byte[] bytes = output.toBytes();
logger.debug("Object serialized to Kryo successfully, length: {}", bytes.length);
return bytes;
} catch (Exception e) {
logger.error("Error serializing object to Kryo", e);
throw new SerializationException("Failed to serialize object to Kryo", e);
}
}
@Override
public void close() {
logger.info("Closing Kryo serializer");
kryoThreadLocal.remove();
outputThreadLocal.remove();
}
}
// 具体策略 - 字符串序列化器
public class StringSerializer implements Serializer<String> {
private final String encoding;
private final Logger logger = LoggerFactory.getLogger(StringSerializer.class);
public StringSerializer() {
this("UTF-8");
}
public StringSerializer(String encoding) {
this.encoding = encoding;
}
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
logger.info("Configuring String serializer, encoding: {}, isKey: {}", encoding, isKey);
}
@Override
public byte[] serialize(String topic, String data) {
if (data == null) {
return null;
}
try {
logger.debug("Serializing string for topic: {}", topic);
byte[] bytes = data.getBytes(encoding);
logger.debug("String serialized successfully, length: {}", bytes.length);
return bytes;
} catch (Exception e) {
logger.error("Error serializing string", e);
throw new SerializationException("Failed to serialize string", e);
}
}
@Override
public void close() {
logger.info("Closing String serializer");
}
}
// 具体策略 - 长整型序列化器
public class LongSerializer implements Serializer<Long> {
private final Logger logger = LoggerFactory.getLogger(LongSerializer.class);
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
logger.info("Configuring Long serializer, isKey: {}", isKey);
}
@Override
public byte[] serialize(String topic, Long data) {
if (data == null) {
return null;
}
try {
logger.debug("Serializing long for topic: {}", topic);
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(data);
byte[] bytes = buffer.array();
logger.debug("Long serialized successfully, length: {}", bytes.length);
return bytes;
} catch (Exception e) {
logger.error("Error serializing long", e);
throw new SerializationException("Failed to serialize long", e);
}
}
@Override
public void close() {
logger.info("Closing Long serializer");
}
}
// 上下文 - 序列化策略管理器
public class SerializationStrategyManager {
private final Map<String, Serializer<?>> serializers = new HashMap<>();
private Serializer<?> defaultSerializer;
private final Logger logger = LoggerFactory.getLogger(SerializationStrategyManager.class);
public SerializationStrategyManager() {
// 注册默认序列化器
serializers.put("string", new StringSerializer());
serializers.put("long", new LongSerializer());
serializers.put("json", new JsonSerializer<>());
serializers.put("kryo", new KryoSerializer<>());
defaultSerializer = serializers.get("json");
}
public void registerSerializer(String name, Serializer<?> serializer) {
serializers.put(name, serializer);
logger.info("Registered serializer: {}", name);
}
public void setDefaultSerializer(String name) {
Serializer<?> serializer = serializers.get(name);
if (serializer != null) {
defaultSerializer = serializer;
logger.info("Set default serializer to: {}", name);
}
}
@SuppressWarnings("unchecked")
public <T> Serializer<T> getSerializer(String name) {
return (Serializer<T>) serializers.get(name);
}
@SuppressWarnings("unchecked")
public <T> Serializer<T> getDefaultSerializer() {
return (Serializer<T>) defaultSerializer;
}
public List<String> getAvailableSerializers() {
return new ArrayList<>(serializers.keySet());
}
}
Kafka Partition Assignment Strategy Pattern
// Kafka分区分配策略模式 - 分区分配策略接口
public interface PartitionAssignor {
// 分配分区
Map<String, Assignment> assign(Cluster metadata, Map<String, Subscription> subscriptions);
// 获取分配器名称
String name();
// 订阅信息
Subscription subscription(Set<String> topics);
// 分配信息
Assignment assignment(List<TopicPartition> partitions);
}
// 具体策略 - 范围分配策略
public class RangeAssignor implements PartitionAssignor {
private final Logger logger = LoggerFactory.getLogger(RangeAssignor.class);
@Override
public Map<String, Assignment> assign(Cluster metadata, Map<String, Subscription> subscriptions) {
logger.info("Performing range partition assignment");
Map<String, Assignment> assignments = new HashMap<>();
for (Map.Entry<String, Subscription> entry : subscriptions.entrySet()) {
String consumerId = entry.getKey();
Subscription subscription = entry.getValue();
List<TopicPartition> assignedPartitions = new ArrayList<>();
for (String topic : subscription.topics()) {
List<PartitionInfo> partitions = metadata.partitionsForTopic(topic);
if (partitions != null && !partitions.isEmpty()) {
// 范围分配逻辑
int partitionCount = partitions.size();
int consumerIndex = getConsumerIndex(consumerId, subscriptions.keySet());
int partitionsPerConsumer = partitionCount / subscriptions.size();
int start = consumerIndex * partitionsPerConsumer;
int end = (consumerIndex == subscriptions.size() - 1) ?
partitionCount : start + partitionsPerConsumer;
for (int i = start; i < end; i++) {
assignedPartitions.add(new TopicPartition(topic, i));
}
}
}
assignments.put(consumerId, new Assignment(assignedPartitions));
logger.info("Assigned {} partitions to consumer: {}", assignedPartitions.size(), consumerId);
}
return assignments;
}
@Override
public String name() {
return "range";
}
@Override
public Subscription subscription(Set<String> topics) {
return new Subscription(new ArrayList<>(topics));
}
@Override
public Assignment assignment(List<TopicPartition> partitions) {
return new Assignment(partitions);
}
private int getConsumerIndex(String consumerId, Set<String> consumerIds) {
List<String> sortedConsumers = new ArrayList<>(consumerIds);
Collections.sort(sortedConsumers);
return sortedConsumers.indexOf(consumerId);
}
}
// 具体策略 - 轮询分配策略
public class RoundRobinAssignor implements PartitionAssignor {
private final Logger logger = LoggerFactory.getLogger(RoundRobinAssignor.class);
@Override
public Map<String, Assignment> assign(Cluster metadata, Map<String, Subscription> subscriptions) {
logger.info("Performing round-robin partition assignment");
Map<String, Assignment> assignments = new HashMap<>();
// 收集所有分区
List<TopicPartition> allPartitions = new ArrayList<>();
for (Subscription subscription : subscriptions.values()) {
for (String topic : subscription.topics()) {
List<PartitionInfo> partitions = metadata.partitionsForTopic(topic);
if (partitions != null) {
for (PartitionInfo partition : partitions) {
allPartitions.add(new TopicPartition(topic, partition.partition()));
}
}
}
}
// 轮询分配
List<String> consumers = new ArrayList<>(subscriptions.keySet());
Collections.sort(consumers);
for (int i = 0; i < allPartitions.size(); i++) {
TopicPartition partition = allPartitions.get(i);
String consumerId = consumers.get(i % consumers.size());
Assignment assignment = assignments.computeIfAbsent(consumerId,
k -> new Assignment(new ArrayList<>()));
assignment.partitions().add(partition);
}
logger.info("Round-robin assignment completed for {} partitions across {} consumers",
allPartitions.size(), consumers.size());
return assignments;
}
@Override
public String name() {
return "roundrobin";
}
@Override
public Subscription subscription(Set<String> topics) {
return new Subscription(new ArrayList<>(topics));
}
@Override
public Assignment assignment(List<TopicPartition> partitions) {
return new Assignment(partitions);
}
}
// 具体策略 - 粘性分配策略
public class StickyAssignor implements PartitionAssignor {
private final Logger logger = LoggerFactory.getLogger(StickyAssignor.class);
@Override
public Map<String, Assignment> assign(Cluster metadata, Map<String, Subscription> subscriptions) {
logger.info("Performing sticky partition assignment");
Map<String, Assignment> assignments = new HashMap<>();
// 获取之前的分配信息
Map<String, List<TopicPartition>> previousAssignment = getPreviousAssignment(subscriptions);
// 尽量保持之前的分配
Set<TopicPartition> assignedPartitions = new HashSet<>();
for (Map.Entry<String, Subscription> entry : subscriptions.entrySet()) {
String consumerId = entry.getKey();
List<TopicPartition> previousPartitions = previousAssignment.get(consumerId);
List<TopicPartition> newPartitions = new ArrayList<>();
if (previousPartitions != null) {
// 保留之前分配的分区
for (TopicPartition partition : previousPartitions) {
if (isPartitionAvailable(partition, metadata, entry.getValue().topics())) {
newPartitions.add(partition);
assignedPartitions.add(partition);
}
}
}
// 分配剩余的分区
List<TopicPartition> remainingPartitions = getRemainingPartitions(metadata,
entry.getValue().topics(), assignedPartitions);
newPartitions.addAll(remainingPartitions);
assignments.put(consumerId, new Assignment(newPartitions));
logger.info("Sticky assigned {} partitions to consumer: {}", newPartitions.size(), consumerId);
}
return assignments;
}
@Override
public String name() {
return "sticky";
}
@Override
public Subscription subscription(Set<String> topics) {
return new Subscription(new ArrayList<>(topics));
}
@Override
public Assignment assignment(List<TopicPartition> partitions) {
return new Assignment(partitions);
}
private Map<String, List<TopicPartition>> getPreviousAssignment(Map<String, Subscription> subscriptions) {
// 从订阅信息中获取之前的分配
Map<String, List<TopicPartition>> previousAssignment = new HashMap<>();
for (Map.Entry<String, Subscription> entry : subscriptions.entrySet()) {
// 这里简化处理,实际应该从订阅信息中提取
previousAssignment.put(entry.getKey(), new ArrayList<>());
}
return previousAssignment;
}
private boolean isPartitionAvailable(TopicPartition partition, Cluster metadata, List<String> subscribedTopics) {
return subscribedTopics.contains(partition.topic()) &&
metadata.partition(partition) != null;
}
private List<TopicPartition> getRemainingPartitions(Cluster metadata, List<String> topics,
Set<TopicPartition> assignedPartitions) {
List<TopicPartition> remaining = new ArrayList<>();
for (String topic : topics) {
List<PartitionInfo> partitions = metadata.partitionsForTopic(topic);
if (partitions != null) {
for (PartitionInfo partition : partitions) {
TopicPartition tp = new TopicPartition(topic, partition.partition());
if (!assignedPartitions.contains(tp)) {
remaining.add(tp);
}
}
}
}
return remaining;
}
}
// 具体策略 - 协作粘性分配策略
public class CooperativeStickyAssignor implements PartitionAssignor {
private final StickyAssignor stickyAssignor = new StickyAssignor();
private final Logger logger = LoggerFactory.getLogger(CooperativeStickyAssignor.class);
@Override
public Map<String, Assignment> assign(Cluster metadata, Map<String, Subscription> subscriptions) {
logger.info("Performing cooperative sticky partition assignment");
// 首先使用粘性分配
Map<String, Assignment> assignments = stickyAssignor.assign(metadata, subscriptions);
// 协作处理:尽量减少分区重新分配
for (Map.Entry<String, Assignment> entry : assignments.entrySet()) {
Assignment assignment = entry.getValue();
// 这里可以添加协作逻辑,如逐步重新分配
logger.debug("Cooperative assignment for consumer {}: {} partitions",
entry.getKey(), assignment.partitions().size());
}
return assignments;
}
@Override
public String name() {
return "cooperative-sticky";
}
@Override
public Subscription subscription(Set<String> topics) {
return stickyAssignor.subscription(topics);
}
@Override
public Assignment assignment(List<TopicPartition> partitions) {
return stickyAssignor.assignment(partitions);
}
}
// 上下文 - 分区分配策略管理器
public class PartitionAssignmentStrategyManager {
private final Map<String, PartitionAssignor> assignors = new HashMap<>();
private PartitionAssignor defaultAssignor;
private final Logger logger = LoggerFactory.getLogger(PartitionAssignmentStrategyManager.class);
public PartitionAssignmentStrategyManager() {
// 注册默认分配策略
assignors.put("range", new RangeAssignor());
assignors.put("roundrobin", new RoundRobinAssignor());
assignors.put("sticky", new StickyAssignor());
assignors.put("cooperative-sticky", new CooperativeStickyAssignor());
defaultAssignor = assignors.get("range");
}
public void registerAssignor(String name, PartitionAssignor assignor) {
assignors.put(name, assignor);
logger.info("Registered partition assignor: {}", name);
}
public void setDefaultAssignor(String name) {
PartitionAssignor assignor = assignors.get(name);
if (assignor != null) {
defaultAssignor = assignor;
logger.info("Set default partition assignor to: {}", name);
}
}
public PartitionAssignor getAssignor(String name) {
return assignors.get(name);
}
public PartitionAssignor getDefaultAssignor() {
return defaultAssignor;
}
public List<String> getAvailableAssignors() {
return new ArrayList<>(assignors.keySet());
}
}
9. Redis
Redis Data Structure Strategy Pattern
// Redis数据结构策略模式 - 数据结构策略接口
public interface RedisDataStructureStrategy<T> {
// 存储数据
void set(String key, T value);
// 获取数据
T get(String key);
// 删除数据
void delete(String key);
// 检查是否存在
boolean exists(String key);
// 获取策略类型
String getStrategyType();
}
// 具体策略 - 字符串数据结构
public class RedisStringStrategy implements RedisDataStructureStrategy<String> {
private final Jedis jedis;
private final Logger logger = LoggerFactory.getLogger(RedisStringStrategy.class);
public RedisStringStrategy(Jedis jedis) {
this.jedis = jedis;
}
@Override
public void set(String key, String value) {
logger.debug("Setting string value for key: {}", key);
jedis.set(key, value);
logger.info("String value set successfully for key: {}", key);
}
@Override
public String get(String key) {
logger.debug("Getting string value for key: {}", key);
String value = jedis.get(key);
logger.info("String value retrieved for key: {}, exists: {}", key, value != null);
return value;
}
@Override
public void delete(String key) {
logger.debug("Deleting string value for key: {}", key);
jedis.del(key);
logger.info("String value deleted for key: {}", key);
}
@Override
public boolean exists(String key) {
boolean exists = jedis.exists(key);
logger.debug("Checking existence for key: {}, exists: {}", key, exists);
return exists;
}
@Override
public String getStrategyType() {
return "STRING";
}
}
// 具体策略 - 列表数据结构
public class RedisListStrategy implements RedisDataStructureStrategy<List<String>> {
private final Jedis jedis;
private final Logger logger = LoggerFactory.getLogger(RedisListStrategy.class);
public RedisListStrategy(Jedis jedis) {
this.jedis = jedis;
}
@Override
public void set(String key, List<String> value) {
logger.debug("Setting list value for key: {}, size: {}", key, value.size());
jedis.del(key); // 先删除旧数据
for (String item : value) {
jedis.rpush(key, item);
}
logger.info("List value set successfully for key: {}", key);
}
@Override
public List<String> get(String key) {
logger.debug("Getting list value for key: {}", key);
List<String> value = jedis.lrange(key, 0, -1);
logger.info("List value retrieved for key: {}, size: {}", key, value.size());
return value;
}
@Override
public void delete(String key) {
logger.debug("Deleting list value for key: {}", key);
jedis.del(key);
logger.info("List value deleted for key: {}", key);
}
@Override
public boolean exists(String key) {
boolean exists = jedis.exists(key);
logger.debug("Checking existence for key: {}, exists: {}", key, exists);
return exists;
}
@Override
public String getStrategyType() {
return "LIST";
}
}
// 具体策略 - 集合数据结构
public class RedisSetStrategy implements RedisDataStructureStrategy<Set<String>> {
private final Jedis jedis;
private final Logger logger = LoggerFactory.getLogger(RedisSetStrategy.class);
public RedisSetStrategy(Jedis jedis) {
this.jedis = jedis;
}
@Override
public void set(String key, Set<String> value) {
logger.debug("Setting set value for key: {}, size: {}", key, value.size());
jedis.del(key); // 先删除旧数据
for (String item : value) {
jedis.sadd(key, item);
}
logger.info("Set value set successfully for key: {}", key);
}
@Override
public Set<String> get(String key) {
logger.debug("Getting set value for key: {}", key);
Set<String> value = jedis.smembers(key);
logger.info("Set value retrieved for key: {}, size: {}", key, value.size());
return value;
}
@Override
public void delete(String key) {
logger.debug("Deleting set value for key: {}", key);
jedis.del(key);
logger.info("Set value deleted for key: {}", key);
}
@Override
public boolean exists(String key) {
boolean exists = jedis.exists(key);
logger.debug("Checking existence for key: {}, exists: {}", key, exists);
return exists;
}
@Override
public String getStrategyType() {
return "SET";
}
}
// 具体策略 - 哈希数据结构
public class RedisHashStrategy implements RedisDataStructureStrategy<Map<String, String>> {
private final Jedis jedis;
private final Logger logger = LoggerFactory.getLogger(RedisHashStrategy.class);
public RedisHashStrategy(Jedis jedis) {
this.jedis = jedis;
}
@Override
public void set(String key, Map<String, String> value) {
logger.debug("Setting hash value for key: {}, fields: {}", key, value.size());
jedis.del(key); // 先删除旧数据
jedis.hmset(key, value);
logger.info("Hash value set successfully for key: {}", key);
}
@Override
public Map<String, String> get(String key) {
logger.debug("Getting hash value for key: {}", key);
Map<String, String> value = jedis.hgetAll(key);
logger.info("Hash value retrieved for key: {}, fields: {}", key, value.size());
return value;
}
@Override
public void delete(String key) {
logger.debug("Deleting hash value for key: {}", key);
jedis.del(key);
logger.info("Hash value deleted for key: {}", key);
}
@Override
public boolean exists(String key) {
boolean exists = jedis.exists(key);
logger.debug("Checking existence for key: {}, exists: {}", key, exists);
return exists;
}
@Override
public String getStrategyType() {
return "HASH";
}
}
// 具体策略 - 有序集合数据结构
public class RedisZSetStrategy implements RedisDataStructureStrategy<Map<String, Double>> {
private final Jedis jedis;
private final Logger logger = LoggerFactory.getLogger(RedisZSetStrategy.class);
public RedisZSetStrategy(Jedis jedis) {
this.jedis = jedis;
}
@Override
public void set(String key, Map<String, Double> value) {
logger.debug("Setting sorted set value for key: {}, members: {}", key, value.size());
jedis.del(key); // 先删除旧数据
for (Map.Entry<String, Double> entry : value.entrySet()) {
jedis.zadd(key, entry.getValue(), entry.getKey());
}
logger.info("Sorted set value set successfully for key: {}", key);
}
@Override
public Map<String, Double> get(String key) {
logger.debug("Getting sorted set value for key: {}", key);
Set<Tuple> tuples = jedis.zrangeWithScores(key, 0, -1);
Map<String, Double> value = new LinkedHashMap<>();
for (Tuple tuple : tuples) {
value.put(tuple.getElement(), tuple.getScore());
}
logger.info("Sorted set value retrieved for key: {}, members: {}", key, value.size());
return value;
}
@Override
public void delete(String key) {
logger.debug("Deleting sorted set value for key: {}", key);
jedis.del(key);
logger.info("Sorted set value deleted for key: {}", key);
}
@Override
public boolean exists(String key) {
boolean exists = jedis.exists(key);
logger.debug("Checking existence for key: {}, exists: {}", key, exists);
return exists;
}
@Override
public String getStrategyType() {
return "ZSET";
}
}
// 上下文 - Redis数据结构管理器
public class RedisDataStructureManager {
private final Jedis jedis;
private final Map<String, RedisDataStructureStrategy<?>> strategies = new HashMap<>();
private final Logger logger = LoggerFactory.getLogger(RedisDataStructureManager.class);
public RedisDataStructureManager(Jedis jedis) {
this.jedis = jedis;
// 注册默认策略
strategies.put("string", new RedisStringStrategy(jedis));
strategies.put("list", new RedisListStrategy(jedis));
strategies.put("set", new RedisSetStrategy(jedis));
strategies.put("hash", new RedisHashStrategy(jedis));
strategies.put("zset", new RedisZSetStrategy(jedis));
}
public void registerStrategy(String name, RedisDataStructureStrategy<?> strategy) {
strategies.put(name, strategy);
logger.info("Registered Redis data structure strategy: {}", name);
}
@SuppressWarnings("unchecked")
public <T> RedisDataStructureStrategy<T> getStrategy(String name) {
return (RedisDataStructureStrategy<T>) strategies.get(name);
}
public <T> void setData(String structureType, String key, T value) {
RedisDataStructureStrategy<T> strategy = getStrategy(structureType);
if (strategy != null) {
logger.info("Setting data using strategy: {}, key: {}", structureType, key);
strategy.set(key, value);
} else {
throw new IllegalArgumentException("Unknown strategy type: " + structureType);
}
}
@SuppressWarnings("unchecked")
public <T> T getData(String structureType, String key) {
RedisDataStructureStrategy<T> strategy = getStrategy(structureType);
if (strategy != null) {
logger.info("Getting data using strategy: {}, key: {}", structureType, key);
return strategy.get(key);
} else {
throw new IllegalArgumentException("Unknown strategy type: " + structureType);
}
}
public void deleteData(String structureType, String key) {
RedisDataStructureStrategy<?> strategy = getStrategy(structureType);
if (strategy != null) {
logger.info("Deleting data using strategy: {}, key: {}", structureType, key);
strategy.delete(key);
} else {
throw new IllegalArgumentException("Unknown strategy type: " + structureType);
}
}
public boolean exists(String structureType, String key) {
RedisDataStructureStrategy<?> strategy = getStrategy(structureType);
if (strategy != null) {
return strategy.exists(key);
} else {
throw new IllegalArgumentException("Unknown strategy type: " + structureType);
}
}
public List<String> getAvailableStrategies() {
return new ArrayList<>(strategies.keySet());
}
}
10. Elasticsearch
Elasticsearch Query Strategy Pattern
// Elasticsearch查询策略模式 - 查询策略接口
public interface ElasticsearchQueryStrategy<T> {
// 执行查询
SearchResponse executeQuery(String index, T queryParams) throws IOException;
// 构建查询
QueryBuilder buildQuery(T queryParams);
// 获取策略类型
String getStrategyType();
}
// 具体策略 - 匹配查询
public class MatchQueryStrategy implements ElasticsearchQueryStrategy<Map<String, Object>> {
private final RestHighLevelClient client;
private final Logger logger = LoggerFactory.getLogger(MatchQueryStrategy.class);
public MatchQueryStrategy(RestHighLevelClient client) {
this.client = client;
}
@Override
public SearchResponse executeQuery(String index, Map<String, Object> queryParams) throws IOException {
logger.info("Executing match query on index: {}, params: {}", index, queryParams);
SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 构建匹配查询
String field = (String) queryParams.get("field");
String value = (String) queryParams.get("value");
Float boost = (Float) queryParams.getOrDefault("boost", 1.0f);
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(field, value).boost(boost);
sourceBuilder.query(matchQuery);
// 设置分页
Integer from = (Integer) queryParams.getOrDefault("from", 0);
Integer size = (Integer) queryParams.getOrDefault("size", 10);
sourceBuilder.from(from).size(size);
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
logger.info("Match query completed, hits: {}", response.getHits().getTotalHits());
return response;
}
@Override
public QueryBuilder buildQuery(Map<String, Object> queryParams) {
String field = (String) queryParams.get("field");
String value = (String) queryParams.get("value");
Float boost = (Float) queryParams.getOrDefault("boost", 1.0f);
return QueryBuilders.matchQuery(field, value).boost(boost);
}
@Override
public String getStrategyType() {
return "MATCH_QUERY";
}
}
// 具体策略 - 范围查询
public class RangeQueryStrategy implements ElasticsearchQueryStrategy<Map<String, Object>> {
private final RestHighLevelClient client;
private final Logger logger = LoggerFactory.getLogger(RangeQueryStrategy.class);
public RangeQueryStrategy(RestHighLevelClient client) {
this.client = client;
}
@Override
public SearchResponse executeQuery(String index, Map<String, Object> queryParams) throws IOException {
logger.info("Executing range query on index: {}, params: {}", index, queryParams);
SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 构建范围查询
String field = (String) queryParams.get("field");
Object from = queryParams.get("from");
Object to = queryParams.get("to");
Boolean includeLower = (Boolean) queryParams.getOrDefault("include_lower", true);
Boolean includeUpper = (Boolean) queryParams.getOrDefault("include_upper", true);
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(field);
if (from != null) rangeQuery.from(from).includeLower(includeLower);
if (to != null) rangeQuery.to(to).includeUpper(includeUpper);
sourceBuilder.query(rangeQuery);
// 设置排序
String sortField = (String) queryParams.get("sort_field");
String sortOrder = (String) queryParams.getOrDefault("sort_order", "asc");
if (sortField != null) {
sourceBuilder.sort(sortField, SortOrder.fromString(sortOrder));
}
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
logger.info("Range query completed, hits: {}", response.getHits().getTotalHits());
return response;
}
@Override
public QueryBuilder buildQuery(Map<String, Object> queryParams) {
String field = (String) queryParams.get("field");
Object from = queryParams.get("from");
Object to = queryParams.get("to");
Boolean includeLower = (Boolean) queryParams.getOrDefault("include_lower", true);
Boolean includeUpper = (Boolean) queryParams.getOrDefault("include_upper", true);
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(field);
if (from != null) rangeQuery.from(from).includeLower(includeLower);
if (to != null) rangeQuery.to(to).includeUpper(includeUpper);
return rangeQuery;
}
@Override
public String getStrategyType() {
return "RANGE_QUERY";
}
}
// 具体策略 - 布尔查询
public class BoolQueryStrategy implements ElasticsearchQueryStrategy<Map<String, Object>> {
private final RestHighLevelClient client;
private final Logger logger = LoggerFactory.getLogger(BoolQueryStrategy.class);
public BoolQueryStrategy(RestHighLevelClient client) {
this.client = client;
}
@Override
public SearchResponse executeQuery(String index, Map<String, Object> queryParams) throws IOException {
logger.info("Executing bool query on index: {}, params: {}", index, queryParams);
SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 构建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加must条件
List<Map<String, Object>> mustConditions = (List<Map<String, Object>>) queryParams.get("must");
if (mustConditions != null) {
for (Map<String, Object> condition : mustConditions) {
boolQuery.must(buildConditionQuery(condition));
}
}
// 添加should条件
List<Map<String, Object>> shouldConditions = (List<Map<String, Object>>) queryParams.get("should");
if (shouldConditions != null) {
for (Map<String, Object> condition : shouldConditions) {
boolQuery.should(buildConditionQuery(condition));
}
Integer minimumShouldMatch = (Integer) queryParams.get("minimum_should_match");
if (minimumShouldMatch != null) {
boolQuery.minimumShouldMatch(minimumShouldMatch);
}
}
// 添加must_not条件
List<Map<String, Object>> mustNotConditions = (List<Map<String, Object>>) queryParams.get("must_not");
if (mustNotConditions != null) {
for (Map<String, Object> condition : mustNotConditions) {
boolQuery.mustNot(buildConditionQuery(condition));
}
}
// 添加filter条件
List<Map<String, Object>> filterConditions = (List<Map<String, Object>>) queryParams.get("filter");
if (filterConditions != null) {
for (Map<String, Object> condition : filterConditions) {
boolQuery.filter(buildConditionQuery(condition));
}
}
sourceBuilder.query(boolQuery);
// 设置高亮
Boolean highlight = (Boolean) queryParams.get("highlight");
if (highlight != null && highlight) {
HighlightBuilder highlightBuilder = new HighlightBuilder();
List<String> highlightFields = (List<String>) queryParams.get("highlight_fields");
if (highlightFields != null) {
for (String field : highlightFields) {
highlightBuilder.field(field);
}
}
sourceBuilder.highlighter(highlightBuilder);
}
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
logger.info("Bool query completed, hits: {}", response.getHits().getTotalHits());
return response;
}
private QueryBuilder buildConditionQuery(Map<String, Object> condition) {
String type = (String) condition.get("type");
switch (type) {
case "match":
return QueryBuilders.matchQuery((String) condition.get("field"), condition.get("value"));
case "term":
return QueryBuilders.termQuery((String) condition.get("field"), condition.get("value"));
case "range":
return QueryBuilders.rangeQuery((String) condition.get("field"))
.from(condition.get("from"))
.to(condition.get("to"));
default:
throw new IllegalArgumentException("Unknown condition type: " + type);
}
}
@Override
public QueryBuilder buildQuery(Map<String, Object> queryParams) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 这里简化处理,实际应该构建完整的布尔查询
List<Map<String, Object>> mustConditions = (List<Map<String, Object>>) queryParams.get("must");
if (mustConditions != null) {
for (Map<String, Object> condition : mustConditions) {
boolQuery.must(buildConditionQuery(condition));
}
}
return boolQuery;
}
@Override
public String getStrategyType() {
return "BOOL_QUERY";
}
}
// 具体策略 - 聚合查询
public class AggregationQueryStrategy implements ElasticsearchQueryStrategy<Map<String, Object>> {
private final RestHighLevelClient client;
private final Logger logger = LoggerFactory.getLogger(AggregationQueryStrategy.class);
public AggregationQueryStrategy(RestHighLevelClient client) {
this.client = client;
}
@Override
public SearchResponse executeQuery(String index, Map<String, Object> queryParams) throws IOException {
logger.info("Executing aggregation query on index: {}, params: {}", index, queryParams);
SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 构建聚合查询
Map<String, Object> aggregations = (Map<String, Object>) queryParams.get("aggregations");
if (aggregations != null) {
for (Map.Entry<String, Object> entry : aggregations.entrySet()) {
String aggName = entry.getKey();
Map<String, Object> aggConfig = (Map<String, Object>) entry.getValue();
AggregationBuilder aggregationBuilder = buildAggregation(aggName, aggConfig);
sourceBuilder.aggregation(aggregationBuilder);
}
}
// 设置查询条件(可选)
Map<String, Object> query = (Map<String, Object>) queryParams.get("query");
if (query != null) {
sourceBuilder.query(buildQuery(query));
}
// 设置size为0,只返回聚合结果
sourceBuilder.size(0);
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
logger.info("Aggregation query completed, aggregations: {}", response.getAggregations().getAsMap().size());
return response;
}
private AggregationBuilder buildAggregation(String name, Map<String, Object> config) {
String type = (String) config.get("type");
String field = (String) config.get("field");
switch (type) {
case "terms":
return AggregationBuilders.terms(name).field(field);
case "avg":
return AggregationBuilders.avg(name).field(field);
case "sum":
return AggregationBuilders.sum(name).field(field);
case "max":
return AggregationBuilders.max(name).field(field);
case "min":
return AggregationBuilders.min(name).field(field);
case "date_histogram":
String interval = (String) config.get("interval");
return AggregationBuilders.dateHistogram(name).field(field).calendarInterval(
DateHistogramInterval.valueOf(interval));
default:
throw new IllegalArgumentException("Unknown aggregation type: " + type);
}
}
private QueryBuilder buildQuery(Map<String, Object> queryParams) {
// 简化处理,实际应该构建完整的查询
return QueryBuilders.matchAllQuery();
}
@Override
public QueryBuilder buildQuery(Map<String, Object> queryParams) {
return QueryBuilders.matchAllQuery(); // 聚合查询通常使用match_all
}
@Override
public String getStrategyType() {
return "AGGREGATION_QUERY";
}
}
// 上下文 - Elasticsearch查询策略管理器
public class ElasticsearchQueryStrategyManager {
private final Map<String, ElasticsearchQueryStrategy<?>> strategies = new HashMap<>();
private final RestHighLevelClient client;
private final Logger logger = LoggerFactory.getLogger(ElasticsearchQueryStrategyManager.class);
public ElasticsearchQueryStrategyManager(RestHighLevelClient client) {
this.client = client;
// 注册默认策略
strategies.put("match", new MatchQueryStrategy(client));
strategies.put("range", new RangeQueryStrategy(client));
strategies.put("bool", new BoolQueryStrategy(client));
strategies.put("aggregation", new AggregationQueryStrategy(client));
}
public void registerStrategy(String name, ElasticsearchQueryStrategy<?> strategy) {
strategies.put(name, strategy);
logger.info("Registered Elasticsearch query strategy: {}", name);
}
@SuppressWarnings("unchecked")
public <T> ElasticsearchQueryStrategy<T> getStrategy(String name) {
return (ElasticsearchQueryStrategy<T>) strategies.get(name);
}
public <T> SearchResponse executeQuery(String strategyName, String index, T queryParams) throws IOException {
ElasticsearchQueryStrategy<T> strategy = getStrategy(strategyName);
if (strategy != null) {
logger.info("Executing query using strategy: {}, index: {}", strategyName, index);
return strategy.executeQuery(index, queryParams);
} else {
throw new IllegalArgumentException("Unknown query strategy: " + strategyName);
}
}
public <T> QueryBuilder buildQuery(String strategyName, T queryParams) {
ElasticsearchQueryStrategy<T> strategy = getStrategy(strategyName);
if (strategy != null) {
return strategy.buildQuery(queryParams);
} else {
throw new IllegalArgumentException("Unknown query strategy: " + strategyName);
}
}
public List<String> getAvailableStrategies() {
return new ArrayList<>(strategies.keySet());
}
}
总结
这些实例展示了策略模式在现代分布式系统、消息队列、缓存系统和搜索引擎中的广泛应用,每个实例都包含了完整的策略接口、具体策略实现和上下文管理,提供了灵活的配置和扩展机制。
策略模式在开源框架中应用广泛,主要场景包括:
- 算法选择:提供不同的算法实现,允许运行时选择
- 排序和比较:提供不同的排序和比较策略
- 缓存策略:提供不同的缓存加载和过期策略
- 限流策略:提供不同的限流算法实现
- 负载均衡:提供不同的负载均衡算法
- 日志记录:提供不同的日志输出目标
- 编码和加密:提供不同的编码和加密算法
- 重定向处理:提供不同的HTTP重定向处理策略
策略模式的优点:
- 算法可以自由切换,易于扩展
- 避免使用多重条件判断
- 扩展性良好,增加策略很简单
- 策略类可以复用,减少重复代码
策略模式的缺点:
- 策略类会增多,增加系统复杂度
- 所有策略类都需要对外暴露,客户端必须知道有哪些策略
- 客户端需要理解所有策略的区别,才能选择合适的策略
更多推荐



所有评论(0)