文章目录
在复杂场景使用策略和工厂模式代替分支语句
在软件开发过程中,随着业务逻辑的不断复杂,大量的分支语句往往会让代码变得臃肿、难以维护。而策略模式和工厂模式为我们提供了一种优雅的替代方案,能够有效地提升代码的可扩展性和可维护性。在复杂场景下,使用策略和工厂模式代替分支语句可以带来诸多好处。
直接上效果图
如果代码有几十个if-else
是不是会很崩溃,但是使用策略工厂就能把if-else
直接给优化掉。
工厂模式能够与众多其他设计模式相互融合,共同用于系统设计。例如策略工厂,其作用在于创建策略对象;还有代理工厂,专门用于创建代理对象。以 Spring 的 AOP 代理工厂为例,它会依据目标对象的具体状况,创建 JDK 代理或者 CGLIB 代理。
策略工厂实现 - 支付案例
我是如何把上面的if-else
优化掉的呢。仔细看完代码就会恍然大悟,相信我一定不会后悔。
一、定义策略接口
public interface PaymentStrategy {
/**
* 判断条件是否为true
*/
boolean isSupport(String payMethod);
/**
* 支付方法
*/
void pay(double amount);
}
二、实现对应的策略类
// 支付宝支付
public class AlipayPaymentStrategy implements PaymentStrategy {
@Override
public boolean isSupport(String payMethod) {
return "AlipayPay".equals(payMethod);
}
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元。");
}
}
// paypal支付
public class PayPalPaymentStrategy implements PaymentStrategy {
@Override
public boolean isSupport(String payMethod) {
return "PayPalPay".equals(payMethod);
}
@Override
public void pay(double amount) {
System.out.println("使用 PayPal 支付:" + amount + "元。");
}
}
// 银联支付
public class UnionPayPaymentStrategy implements PaymentStrategy {
@Override
public boolean isSupport(String payMethod) {
return "UnionPay".equals(payMethod);
}
@Override
public void pay(double amount) {
System.out.println("使用银联支付:" + amount + "元。");
}
}
// 微信支付
public class WeChatPaymentStrategy implements PaymentStrategy {
@Override
public boolean isSupport(String payMethod) {
return "WeChatPay".equals(payMethod);
}
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元。");
}
}
三、定义策略工厂
public class PaymentFactory {
private final List<PaymentStrategy> paymentStrategyList = new ArrayList<>();
private static final PaymentFactory factory = new PaymentFactory();
/**
* 单例工厂
*/
public static PaymentFactory getInstance() {
return factory;
}
private PaymentFactory() {
// 注册策略
paymentStrategyList.add(new AlipayPaymentStrategy());
paymentStrategyList.add(new WeChatPaymentStrategy());
paymentStrategyList.add(new UnionPayPaymentStrategy());
paymentStrategyList.add(new PayPalPaymentStrategy());
// 后续有策略,继续添加。也可以使用类扫描或者其他方式添加
}
/**
* 从注册的策略列表中获取策略
*/
public PaymentStrategy getStrategy(String payMethod) {
for (PaymentStrategy paymentStrategy : paymentStrategyList) {
if (paymentStrategy.isSupport(payMethod)) {
return paymentStrategy;
}
}
new Exception("支付方式不支持");
return null;
}
}
四、使用
// 修改之后的使用方式
public void strategyPay(double amount, String payMethod) {
PaymentFactory paymentFactory = PaymentFactory.getInstance();
PaymentStrategy strategy = paymentFactory.getStrategy(payMethod);
strategy.pay(amount);
}
// 修改之前的使用方式
public void pay(double amount, String payMethod) {
if ("AlipayPay".equals(payMethod)) {
System.out.println("使用支付宝支付:" + amount + "元。");
} else if ("PayPalPay".equals(payMethod)) {
System.out.println("使用 PayPal 支付:" + amount + "元。");
} else if ("UnionPay".equals(payMethod)) {
System.out.println("使用银联支付:" + amount + "元。");
} else if ("WeChatPay".equals(payMethod)) {
System.out.println("使用微信支付:" + amount + "元。");
} else {
new Exception("支付方式不支持");
}
}
五、接口测试
@Test
public void testStrategyPay() {
paymentService.strategyPay(100.0, "AlipayPay");
paymentService.strategyPay(100.0, "PayPalPay");
paymentService.strategyPay(100.0, "UnionPay");
paymentService.strategyPay(100.0, "WeChatPay");
}
结果如下
使用支付宝支付:100.0元。
使用 PayPal 支付:100.0元。
使用银联支付:100.0元。
使用微信支付:100.0元。
if-else 真的消失了吗?
表面上看,if-else 似乎消失了,但实际上它只是转移到了策略类中。策略类通常包含两个方法,一个方法对应着条件的判断,另一个方法对应着满足条件后的行为。
工厂模式在一定程度上看似消灭了 if 判断,它通过将对象的创建职责委托给工厂类,根据不同的条件返回不同的对象实例,从而避免了在使用对象的地方出现大量的 if-else 判断。
而策略模式则可以被认为消灭了条件体。策略模式将不同的算法或行为封装在不同的策略类中,通过选择不同的策略类来实现不同的行为,而不是通过传统的 if-else 条件体来决定执行哪种行为。
然而,虽然 if-else 在代码中的表现形式可能发生了变化,但实际上条件判断的逻辑并没有真正消失,只是被转移到了不同的地方进行处理。在设计软件系统时,我们可以根据具体情况选择合适的设计模式来优化代码结构,减少 if-else 的使用,但不能完全消除条件判断的本质。
Spring是如何使用工厂模式和策略模式的
1. BeanFactory 和 ApplicationContext 的实现
工厂模式的应用
在 Spring 中,BeanFactory
和 ApplicationContext
是两个核心接口,用于管理和配置 Spring 应用中的 Beans。这两个接口都是工厂模式的实现,负责创建和管理 Bean 的实例。通过 BeanFactory
或 ApplicationContext
,我们可以获取任何已配置的 Bean,而这些 Bean 的实例化是由 Spring 自动处理的。
- BeanFactory:这是一个基础的容器,提供了基本的 Bean 管理功能。通过
getBean()
方法,可以根据 Bean 的名称或类型获取 Bean 的实例。这种实例化过程由BeanFactory
负责,Bean 的创建、销毁等生命周期管理都由它完成。 - ApplicationContext:这是
BeanFactory
的扩展,提供了更多高级功能,例如事件发布、国际化支持和对 AOP 的集成。ApplicationContext
实际上是工厂模式的扩展和更高级别的实现,它不仅能够创建和管理 Bean,还可以根据上下文来进行更复杂的配置和管理。
策略模式的应用
Spring 中的策略模式通常体现在以下几个方面:
-
@Qualifier 注解:当一个接口有多个实现类时,Spring 使用
@Qualifier
注解来指定注入哪一个具体的实现。这就是策略模式的体现,@Qualifier
允许我们选择不同的实现策略。@Autowired @Qualifier("myServiceImpl") private MyService myService;
通过
@Qualifier
,我们可以选择注入MyService
接口的哪一个具体实现类,从而实现不同的业务逻辑。 -
Condition 接口:Spring 允许根据条件来加载或不加载某个 Bean,这也是策略模式的一种表现。通过实现
Condition
接口,开发者可以定义在某些条件下才加载某个 Bean 的策略。@Bean @Conditional(MyCondition.class) public MyService myService() { return new MyServiceImpl(); }
2. Transaction Management 的实现
工厂模式的应用
Spring 的事务管理依赖于 PlatformTransactionManager
接口。这个接口有多个实现类,比如 DataSourceTransactionManager
、JpaTransactionManager
等。Spring 使用工厂模式通过配置来选择和实例化具体的事务管理器。
-
事务管理器的选择:开发者可以在配置文件中或使用 Java 配置类来指定事务管理器的类型。Spring 会根据配置选择合适的事务管理器并将其实例化。
@Bean public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { return new JpaTransactionManager(emf); }
在这个例子中,
JpaTransactionManager
是通过工厂方法创建的,这个过程由 Spring 管理,开发者无需手动实例化事务管理器。
策略模式的应用
Spring 事务管理框架中的策略模式体现在以下几个方面:
-
事务传播行为:Spring 提供了多种事务传播行为(如
REQUIRED
,REQUIRES_NEW
,SUPPORTS
等),这些行为可以通过注解的方式指定。这些不同的传播行为实际上是不同的策略,可以根据业务需求选择合适的策略。@Transactional(propagation = Propagation.REQUIRED) public void someMethod() { // transactional code here }
这里的
Propagation.REQUIRED
就是策略模式的应用,Spring 会根据这个策略来决定如何处理事务的传播。 -
事务隔离级别:类似地,Spring 也提供了多种事务隔离级别(如
READ_COMMITTED
,REPEATABLE_READ
等),开发者可以选择不同的隔离级别策略来处理并发事务的影响。@Transactional(isolation = Isolation.READ_COMMITTED) public void anotherMethod() { // transactional code here }
通过这些例子,可以看到 Spring 是如何结合使用工厂模式和策略模式来实现灵活、可配置的 Bean 管理和事务管理功能的。这种设计使得 Spring Framework 具有高度的可扩展性和灵活性,能够适应不同的应用需求。
策略工厂 - 总结
当面对复杂场景时,大量的分支语句会让代码变得难以维护和理解。本文以支付案例为例,展示了如果代码中存在几十个if-else语句会带来的困扰。
通过引入策略和工厂模式,成功地将这些繁琐的if-else优化掉。在支付案例中,原本可能令人崩溃的条件判断被策略工厂巧妙替代,极大地提高了代码的可维护性和可读性。
仔细研究代码可以发现,策略模式将不同的支付方式封装成独立的策略类,而工厂模式则负责根据特定条件创建相应的策略对象。这种组合使得代码结构更加清晰,易于扩展和修改。
总之,在复杂场景下,策略和工厂模式为我们提供了一种有效的解决方案,帮助我们摆脱分支语句的困扰,提升软件的质量和可维护性。