一、简介
策略模式(Strategy Pattern)是一种行为设计模式,它允许定义一系列算法,将每个算法封装到独立的类中,并使它们可以相互替换。这使得算法可以独立于使用它们的客户端进行变化。
在策略模式中,算法被视为一个策略。这些策略被封装到各自的类中,并通过接口或抽象类暴露统一的方法,使得这些策略可以相互替换。然后,客户端可以根据需要选择使用的策略。
这种模式使得算法可以独立于其使用者变化。它使得代码更加灵活、可扩展,并且更易于维护,因为新的算法可以在不修改现有客户端代码的情况下添加。
总之,策略模式允许定义一系列算法并使它们可以相互替换,从而提供了更大的灵活性和可扩展性。
二、策略模式
Nginx 支持多种负载均衡策略,你可以根据需要选择适合你应用场景的策略,那些嵌套的ifelse我就不去写了。接下里我们简单演示使用策略模式来选择不同的负载均衡策略。
2.1、负载均衡接口
定义一个策略接口
// 负载均衡策略
public interface LoadBalancingStrategy {
String chooseServer(List<String> servers);
}
2.2、轮询策略
// 轮询策略
public class RoundRobinStrategy implements LoadBalancingStrategy {
private int currentIndex;
public RoundRobinStrategy() {
this.currentIndex = 0;
}
@Override
public String chooseServer(List<String> servers) {
String selectedServer = servers.get(currentIndex);
currentIndex = (currentIndex + 1) % servers.size();
return selectedServer;
}
}
2.3、随机策略
// 随机策略
public class RandomStrategy implements LoadBalancingStrategy {
private Random random;
public RandomStrategy() {
this.random = new Random();
}
@Override
public String chooseServer(List<String> servers) {
int randomIndex = random.nextInt(servers.size());
return servers.get(randomIndex);
}
}
2.4、Hash策略
// hash策略
public class HashStrategy implements LoadBalancingStrategy {
public HashStrategy() {
}
@Override
public String chooseServer(List<String> servers) {
// 在实际应用中,这里可以根据客户端信息计算哈希值
// 这里简化演示,假设使用客户端信息的哈希码模拟
int hashCode = Math.abs(ThreadLocalRandom.current().nextInt());
int index = hashCode % servers.size();
return servers.get(index);
}
}
2.5、策略工厂
策略工厂在这里是可以避免重复创建对象,节省内存,实际你可以根据需求进行相应处理。
public class StrategyFactory {
private static final Map<String, LoadBalancingStrategy> STRATEGY_MAP = new HashMap<>();
static {
STRATEGY_MAP.put("Round", new RoundRobinStrategy());
STRATEGY_MAP.put("Random", new RandomStrategy());
STRATEGY_MAP.put("Hash", new HashStrategy());
}
public static LoadBalancingStrategy getStrategy(String type) {
// 获取策略
if (STRATEGY_MAP.containsKey(type)) {
return STRATEGY_MAP.get(type);
}
return null;
}
}
2.6、使用
演示如果调用不同的策略
import java.util.Arrays;
import java.util.List;
public class StrategyPatternExample {
public static void main(String[] args) {
List<String> servers = Arrays.asList("订单服务1", "订单服务2", "订单服务3");
LoadBalancingStrategy strategy = StrategyFactory.getStrategy("Round");
String selectedServerRoundRobin = strategy.chooseServer(servers);
System.out.println("轮询策略调用的服务: " + selectedServerRoundRobin);
LoadBalancingStrategy randomStrategy = StrategyFactory.getStrategy("Random");
String selectedServerRandom = randomStrategy.chooseServer(servers);
System.out.println("随机策略调用的服务: " + selectedServerRandom);
LoadBalancingStrategy hashStrategy = StrategyFactory.getStrategy("Hash");
String selectedServerHash = hashStrategy.chooseServer(servers);
System.out.println("Hash模式调用的服务: " + selectedServerHash);
}
}
运行结果:
轮询策略调用的服务: 订单服务1
随机策略调用的服务: 订单服务3
Hash模式调用的服务: 订单服务3
轮询策略调用的服务: 订单服务1
随机策略调用的服务: 订单服务3
Hash模式调用的服务: 订单服务2
三、优点与缺点
策略模式的优点和缺点如下:
优点
- 灵活性和可扩展性: 策略模式允许在运行时选择算法,使得算法可以相互替换,从而提供了更大的灵活性和可扩展性。
- 避免条件语句: 策略模式可以减少条件语句的使用,因为每个算法都被封装在单独的类中,使得客户端代码更简洁、可读性更高。
- 单一职责原则: 每个策略类都包含一个独立的算法,符合单一职责原则,使得代码更易于理解和维护。
- 代码复用: 策略模式可以促进代码的重用,因为相似的算法可以被不同的对象使用。
缺点
- 类数量增加: 策略模式可能会增加类的数量,因为每个策略通常需要一个单独的类,可能导致类的数量增加,使得代码复杂化。
- 客户端必须了解所有策略: 客户端需要了解所有的策略类,并在运行时选择合适的策略,可能会增加理解和维护的难度。
- 策略的选择: 如果没有清晰的判断标准或者策略选择逻辑较为复杂,可能会增加使用该模式的复杂度。