定义
策略模式允许在运行时选择算法的行为。它允许你定义一系列算法,并将每个算法封装在单独的类中,使它们可以互相替换。这样,客户端可以在不改变其使用方式的情况下选择要使用的算法。这种模式有助于提高代码的灵活性和可维护性,因为它将不同的算法逻辑与主要的业务逻辑分离开来。
意图
使算法的选择与使用者(客户端)的解耦。它允许在不修改客户端代码的情况下动态地改变或切换算法,通过封装不同的算法,使得它们可以相互替换。这样的设计使得系统更灵活、可扩展,并且更容易维护,因为新增、修改或删除算法不会对客户端造成影响。策略模式还有助于避免代码中大量的条件判断语句,提高了代码的可读性和可维护性。
参与者(角色)
-
Context(上下文):上下文是策略模式的主要组成部分,它持有一个对策略接口的引用,并在运行时可以切换不同的具体策略。上下文通常会将客户端请求委派给所选的策略对象执行。
-
Strategy(策略):策略是一个接口或抽象类,它定义了一系列算法的通用接口。所有具体策略类都必须实现这个接口,确保它们拥有相同的行为。
-
Concrete Strategies(具体策略):具体策略是实现了策略接口的具体类。每个具体策略类都封装了一个特定的算法。
举例
已使用不同的支付方式为例
类图:
这个例子中对应类的角色如下:
PayStrategy接口
public interface PayStrategy {
void pay(double amount);
}
PayContext类
public class PayContext {
private PayStrategy payStrategy;
public PayContext(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public void changeStrategy(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public void execute(double amount){
payStrategy.pay(amount);
}
}
CreditCardPay支付类
@Slf4j
public class CreditCardPay implements PayStrategy {
@Override
public void pay(double amount) {
log.info("使用信用卡支付了:{}元",amount);
}
}
WeiXinPay类
@Slf4j
public class WeiXinPay implements PayStrategy {
@Override
public void pay(double amount) {
log.info("使用微信支付了:{}元",amount);
}
}
AliPay支付类
@Slf4j
public class AliPay implements PayStrategy {
@Override
public void pay(double amount) {
log.info("使用支付宝支付了:{}元",amount);
}
}
测试
public class App {
public static void main(String[] args) {
AliPay aliPay = new AliPay();
PayContext context = new PayContext(aliPay);
context.execute(100);
context.changeStrategy(new WeiXinPay());
context.execute(200);
context.changeStrategy(new CreditCardPay());
context.execute(300);
}
}
优点
-
灵活性: 策略模式允许在运行时动态切换算法或策略,无需修改客户端代码,提供了灵活性和可维护性。
-
可扩展性: 新的策略可以很容易地添加到系统中,不会影响现有的代码结构,从而提供了可扩展性。
-
代码复用: 通过策略模式,不同的算法逻辑被封装在独立的策略类中,可以在多个地方重复使用,促进了代码复用。
-
减少条件判断: 策略模式可以避免大量的条件判断语句,提高了代码的可读性和可维护性。
缺点
-
类数量增加: 每个策略都需要一个单独的类,可能会导致类的数量增加,尤其是当策略较多时,会增加代码复杂度。
-
客户端必须知道所有的策略: 客户端必须了解所有可用的策略并选择使用哪一个,这可能会增加客户端的复杂性。
-
上下文与策略的耦合: 在某些情况下,上下文对象与特定的策略类紧密耦合,可能导致修改上下文对象以适应新策略的引入。
策略模式的应用
springSecuriy认证策略。spring-ouauth2-原理
//设置不同的认证策略
void configure(HttpSecurity httpSecurity) {
AuthenticationManager authenticationManager = (AuthenticationManager)httpSecurity.getSharedObject(AuthenticationManager.class);
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils.getAuthorizationServerSettings(httpSecurity);
OAuth2AuthorizationEndpointFilter authorizationEndpointFilter = new OAuth2AuthorizationEndpointFilter(authenticationManager, authorizationServerSettings.getAuthorizationEndpoint());
List<AuthenticationConverter> authenticationConverters = createDefaultAuthenticationConverters();
if (!this.authorizationRequestConverters.isEmpty()) {
authenticationConverters.addAll(0, this.authorizationRequestConverters);
}
this.authorizationRequestConvertersConsumer.accept(authenticationConverters);
authorizationEndpointFilter.setAuthenticationConverter(new DelegatingAuthenticationConverter(authenticationConverters));
if (this.authorizationResponseHandler != null) {
authorizationEndpointFilter.setAuthenticationSuccessHandler(this.authorizationResponseHandler);
}
if (this.errorResponseHandler != null) {
authorizationEndpointFilter.setAuthenticationFailureHandler(this.errorResponseHandler);
}
if (StringUtils.hasText(this.consentPage)) {
authorizationEndpointFilter.setConsentPage(this.consentPage);
}
if (this.sessionAuthenticationStrategy != null) {
authorizationEndpointFilter.setSessionAuthenticationStrategy(this.sessionAuthenticationStrategy);
}
httpSecurity.addFilterBefore((Filter)this.postProcess(authorizationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
}
分享到: