它允許在運行時根據(jù)需要選擇算法的行為。該模式通過將算法封裝成獨立的類,使得它們可以相互替換,而不影響使用算法的客戶端代碼。
策略模式主要包含以下角色:
- 環(huán)境(Context):環(huán)境對象持有一個策略對象的引用,它提供了一個接口用于執(zhí)行具體的算法。
- 抽象策略(Strategy):定義了策略類的統(tǒng)一接口,用于約束具體策略類的行為。
- 具體策略(Concrete Strategy):實現(xiàn)了抽象策略定義的接口,具體實現(xiàn)算法邏輯。
下面以一個簡單的支付系統(tǒng)為例來說明策略模式的應(yīng)用:
// 抽象策略類
public interface PaymentStrategy {
void pay(double amount);
}
// 具體策略類
public class AliPayStrategy implements PaymentStrategy {
public void pay(double amount) {
System.out.println("使用支付寶支付:" + amount + "元");
// 具體的支付邏輯
}
}
public class WeChatPayStrategy implements PaymentStrategy {
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
// 具體的支付邏輯
}
}
// 環(huán)境類
@Data
@NoArgsConstructor
public class PaymentContext {
private PaymentStrategy strategy;
public void pay(double amount) {
strategy.pay(amount);
}
}
在上述示例中,我們定義了一個抽象策略類PaymentStrategy
,并有兩個具體的策略類AliPayStrategy
和WeChatPayStrategy
分別實現(xiàn)了支付寶支付和微信支付的具體邏輯。
環(huán)境類PaymentContext
持有一個策略對象的引用,并提供了設(shè)置策略和支付方法??蛻舳送ㄟ^設(shè)置不同的策略對象來實現(xiàn)不同的支付方式。這樣,客戶端代碼與具體的支付算法解耦,可以動態(tài)地在運行時切換支付策略。
下面是使用策略模式實現(xiàn)的客戶端代碼:
javaCopy Codepublic class Client {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();
// 使用支付寶支付
PaymentStrategy aliPayStrategy = new AliPayStrategy();
context.setPaymentStrategy(aliPayStrategy);
context.pay(100.0);
// 使用微信支付
PaymentStrategy weChatPayStrategy = new WeChatPayStrategy();
context.setPaymentStrategy(weChatPayStrategy);
context.pay(200.0);
}
}
運行上述客戶端代碼,輸出如下:
Copy Code 使用支付寶支付:100.0 元
使用微信支付:200.0 元
通過策略模式,我們可以輕松地在運行時切換不同的支付方式,而不需要改動客戶端代碼。策略模式將算法的選擇和使用進行了解耦,提高了代碼的靈活性和可維護性。同時,策略模式也符合開閉原則,當(dāng)需要新增一種支付方式時,只需要添加新的具體策略類即可,無需修改原有代碼邏輯。
public class Client {
public static void main(String[] args) {
double price = 100.0;
String type = "normal";
double discount = 1.0;
// 根據(jù)商品類型設(shè)置折扣率
if (type.equals("vip")) {
discount = 0.9;
} else if (type.equals("member")) {
discount = 0.95;
} else if (type.equals("promotion")) {
discount = 0.8;
}
double actualPrice = price * discount;
System.out.println("商品的實際價格為:" + actualPrice);
}
}
上述代碼中,我們根據(jù)商品類型手動設(shè)置相應(yīng)的折扣率,然后計算實際價格。這樣的代碼雖然簡單,但存在以下問題:
- 客戶端代碼與具體的折扣算法高度耦合,如果需要更改算法,例如新增一種商品類型,就需要修改客戶端代碼,這會導(dǎo)致代碼的可維護性變差。
- 沒有遵循開閉原則,當(dāng)需要新增一種商品類型時,就需要修改原有代碼邏輯,這樣會影響到其他代碼的穩(wěn)定性。
因此,采用策略模式能更好地解決這些問題,實現(xiàn)代碼的松耦合和可維護性。
public class CeLue {
public static void main(String[] args) {
double price = 100.0;
String type = "vip";
PayStrategy conType = getPayStrategy(type);
PayContext payContext = new PayContext(conType);
payContext.pay(price);
}
private static PayStrategy getPayStrategy(String type) {
switch (type) {
case "vip":
return new VipType();
default:
return new NormalType();
}
}
}
interface PayStrategy {
void pay(double amount);
}
class NormalType implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("普通支付" + amount + "元");
}
}
class VipType implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("vip支付" + amount * 0.9 + "元");
}
}
class PayContext {
private PayStrategy payStrategy;
public PayContext(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public void pay(double amount) {
payStrategy.pay(amount);
}
}
分享一個案例:統(tǒng)一認證登錄
認證接口類 AuthService
public interface AuthService {
UserExt execute(AuthParamsDto authParamsDto);
}
它的實現(xiàn)類 可以是密碼登錄PasswordAuthServiceImpl 手機號登錄PhoneAuthServiceImpl 微信登錄WxAuthServiceImpl 等,獲取前綴,拼接bean名稱,Spring上下文拿到bean文章來源:http://www.zghlxwxcb.cn/news/detail-807833.html
調(diào)用,我用的是SpringsSecurity框架并重寫了 UserDetailsService文章來源地址http://www.zghlxwxcb.cn/news/detail-807833.html
@Autowired
ApplicationContext applicationContext;
//傳入的是AuthParamsDto的json串
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
AuthParamsDto authParamsDto = null;
try {
//將認證參數(shù)轉(zhuǎn)為AuthParamsDto類型
authParamsDto = JSON.parseObject(s, AuthParamsDto.class);
} catch (Exception e) {
log.info("認證請求不符合項目要求:{}",s);
throw new RuntimeException("認證請求數(shù)據(jù)格式不對");
}
//認證方式
String authType = authParamsDto.getAuthType();
//從spring容器中拿具體的認證bean實例
AuthService authService = applicationContext.getBean(authType + "_authservice", AuthService.class);
//開始認證,認證成功拿到用戶信息
XcUserExt xcUserExt = authService.execute(authParamsDto);
return getUserPrincipal(xcUserExt);
}
@Data
public class AuthParamsDto {
private String username; //用戶名
private String password; //域 用于擴展
private String cellphone;//手機號
private String checkcode;//驗證碼
private String checkcodekey;//驗證碼key
private String authType; // 認證的類型 password:用戶名密碼模式類型 sms:短信模式類型
private Map<String, Object> payload = new HashMap<>();//附加數(shù)據(jù),作為擴展,不同認證類型可擁有不同的附加數(shù)據(jù)。如認證類型為短信時包含smsKey : sms:3d21042d054548b08477142bbca95cfa; 所有情況下都包含clientId
}
到了這里,關(guān)于【設(shè)計模式 行為型】策略模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!