Java策略模式(Strategy Pattern)
策略模式是一种设计模式,它允许在运行时根据需要选择算法。
一:接口和类的组合来实现策略模式
以下是一个简单的 Java 示例,演示了如何使用策略模式:
// 定义一个策略接口
interface PaymentStrategy {
void pay(int amount);
}
// 不同的支付策略实现
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String cvv;
private String expiryDate;
public CreditCardPayment(String cardNumber, String cvv, String expiryDate) {
this.cardNumber = cardNumber;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
@Override
public void pay(int amount) {
// 实现信用卡支付逻辑
System.out.println(amount + " paid with credit card");
}
}
class AliPayPayment implements PaymentStrategy {
private String email;
private String password;
public AliPayPayment(String email, String password) {
this.email = email;
this.password = password;
}
@Override
public void pay(int amount) {
// 实现支付宝支付逻辑
System.out.println(amount + " paid with PayPal");
}
}
// 上下文类,用于设置和应用策略
class PaymentContext {
private PaymentStrategy paymentStrategy;
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void pay(int amount) {
paymentStrategy.pay(amount);
}
}
// 示例使用
public class StrategyPatternExample {
public static void main(String[] args) {
PaymentContext paymentContext = new PaymentContext(new CreditCardPayment("1234 5678 9012 3456", "123", "12/25"));
paymentContext.pay(100); // 使用信用卡支付 100
paymentContext.setPaymentStrategy(new PayPalPayment("example@example.com", "password123"));
paymentContext.pay(50); // 使用 PayPal 支付 50
}
}
PaymentStrategy 接口定义了支付策略的契约,然后 CreditCardPayment 和 PayPalPayment 类分别实现了这个接口。PaymentContext 类用于设置和应用不同的支付策略。在示例的 main 方法中,首先使用信用卡支付了 100,然后切换到 PayPal 支付方式支付了 50。
二:工厂模式+策略模式
PaymentContext 中需要持有一个PaymentStrategy ,在实际的应用场景中,可以使用工厂模式,管理PaymentStrategy 的所有实例对象,然后根据业务需求,从工厂中获取。
//支付工厂
class PaymentFactory {
public static PaymentStrategy createPaymentStrategy(String paymentType) {
switch (paymentType) {
case "creditcard":
return new CreditCardPayment();
case "paypal":
return new PayPalPayment();
// 可以添加更多的支付类型
default:
throw new IllegalArgumentException("Unknown payment type: " + paymentType);
}
}
}
// 示例使用
public class FactoryStrategyPatternExample {
public static void main(String[] args) {
// 根据不同的类型创建对应的策略对象
PaymentStrategy creditCardPayment = PaymentFactory.createPaymentStrategy("creditcard");
PaymentStrategy paypalPayment = PaymentFactory.createPaymentStrategy("paypal");
int amount = 100;
// 使用不同的策略对象进行支付
creditCardPayment.pay(amount); // 使用信用卡支付 100
paypalPayment.pay(amount); // 使用 PayPal 支付 100
}
}
三:枚举类实现策略模式
在Java中,枚举类(Enum)是一种特殊的数据类型,它允许你定义一组命名的常量。
通过在Enum中添加一个抽象方法,用来实现策略模式。
// 定义一个枚举表示不同的支付策略
enum PaymentType {
CREDIT_CARD {
@Override
public void pay(int amount) {
// 实现信用卡支付逻辑
System.out.println(amount + " paid with credit card");
}
},
PAYPAL {
@Override
public void pay(int amount) {
// 实现PayPal支付逻辑
System.out.println(amount + " paid with PayPal");
}
},
// 可以添加更多的支付策略...
// 默认实现,可以选择抛出异常或者提供一个默认的逻辑
DEFAULT {
@Override
public void pay(int amount) {
throw new UnsupportedOperationException("Unknown or unspecified payment type");
// 或者提供一个默认的支付逻辑
// System.out.println("Unsupported payment type");
}
};
// 抽象方法,每个枚举值都需要实现它
public abstract void pay(int amount);
}
// 示例使用
public class EnumStrategyPatternExample {
public static void main(String[] args) {
int amount = 100;
PaymentType.CREDIT_CARD.pay(amount); // 使用信用卡支付 100
PaymentType.PAYPAL.pay(amount); // 使用 PayPal 支付 100
// 测试未知支付类型
PaymentType.UNKNOWN.pay(amount);
}
}
上面代码示例中,在controller或service层,并不能使用参数选择某一个支付方式;所以,我们需要给枚举类添加一些属性,方便我们获取枚举对象;添加一个doPay方法,用于外部统一调用。
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
@Getter
public enum PaymentType {
CREDIT_CARD(1, "信用卡支付") {
@Override
public void pay(int amount) {
// 实现信用卡支付逻辑
System.out.println(amount + " paid with credit card");
}
},
PAYPAL(2, "PayPal支付") {
@Override
public void pay(int amount) {
// 实现PayPal支付逻辑
System.out.println(amount + " paid with PayPal");
}
},
// 可以添加更多的支付策略...
// 默认实现,可以选择抛出异常或者提供一个默认的逻辑
DEFAULT(0, "未知方式") {
@Override
public void pay(int amount) {
//抛出一个异常
throw new Exception("Unknown or unspecified payment type");
// 或者提供一个默认的支付逻辑
// System.out.println("Unsupported payment type");
}
};
//支付方式编码
private Integer payTypeCode;
//支付方式名称
private String payTypeName;
PaymentType(Integer payTypeCode, String payTypeName) {
this.payTypeCode = payTypeCode;
this.payTypeName = payTypeName;
}
private static final Map<Integer, PaymentType> dataMap = new HashMap<>();
static {
for (PaymentType paymentType : PaymentType.values()) {
dataMap.put(paymentType.getPayTypeCode(), paymentType);
}
}
// 抽象方法,每个枚举值都需要实现它
public abstract void pay(int amount);
//外部调用的方法
public static void doPay(Integer payTypeCode, int amount) {
dataMap.get(payTypeCode).pay(amount);
}
}
// 示例使用
public class EnumStrategyPatternExample {
public static void main(String[] args) {
int amount = 100;
PaymentType.doPay(1,amount); // 使用信用卡支付 100
PaymentType.doPay(2,amount); // 使用 PayPal 支付 100
// 测试未知支付类型
PaymentType.doPay(0,amount);
}
}
在实际应用场景中,PaymentType.pay()方法中,根据前端或者方法调用者,传入支付方式和支付金额即可。