【工厂和策略设计模式妙用】解决接口选择与多重if-else 问题
利用工厂和策略模式解决接口选择与多重if-else问题
在软件开发中,我们经常会遇到需要根据不同的条件选择不同实现的情况。传统的if-else或switch-case方式虽然直观,但随着业务逻辑复杂度的增加,会导致代码难以维护和扩展。工厂模式和策略模式的组合可以优雅地解决这个问题。
问题场景
假设我们有一个支付系统,需要根据不同的支付方式(支付宝、微信、银行卡等)调用不同的支付接口。传统实现可能是:
public void pay(String paymentType, BigDecimal amount) {
if ("alipay".equals(paymentType)) {
// 调用支付宝支付逻辑
} else if ("wechat".equals(paymentType)) {
// 调用微信支付逻辑
} else if ("bank".equals(paymentType)) {
// 调用银行卡支付逻辑
}
// 更多支付方式...
}
这种实现方式存在以下问题:
- 违反开闭原则 - 新增支付方式需要修改原有代码
- 代码臃肿 - 随着支付方式增加,方法会越来越长
- 难以维护 - 所有逻辑集中在一个方法中
解决方案:工厂 + 策略模式
1. 定义策略接口
public interface PaymentStrategy {
void pay(BigDecimal amount);
}
2. 实现具体策略类
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 支付宝支付具体实现
System.out.println("使用支付宝支付:" + amount);
}
}
public class WechatPayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 微信支付具体实现
System.out.println("使用微信支付:" + amount);
}
}
public class BankCardStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 银行卡支付具体实现
System.out.println("使用银行卡支付:" + amount);
}
}
3. 创建策略工厂
public class PaymentStrategyFactory {
private static final Map<String, PaymentStrategy> strategies = new HashMap<>();
static {
strategies.put("alipay", new AlipayStrategy());
strategies.put("wechat", new WechatPayStrategy());
strategies.put("bank", new BankCardStrategy());
}
public static PaymentStrategy getStrategy(String paymentType) {
if (paymentType == null || paymentType.isEmpty()) {
throw new IllegalArgumentException("支付类型不能为空");
}
PaymentStrategy strategy = strategies.get(paymentType);
if (strategy == null) {
throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
}
return strategy;
}
}
4. 使用策略模式
public class PaymentService {
public void pay(String paymentType, BigDecimal amount) {
PaymentStrategy strategy = PaymentStrategyFactory.getStrategy(paymentType);
strategy.pay(amount);
}
}
优势分析
- 符合开闭原则:新增支付方式只需添加新的策略类并在工厂中注册,无需修改现有代码
- 代码清晰:每个支付方式的逻辑封装在各自的类中
- 易于维护:支付逻辑分散到各个策略类,降低复杂度
- 可扩展性强:可以轻松添加新的支付方式
- 便于测试:每个策略类可以单独测试
进阶优化
使用Spring框架的依赖注入
如果使用Spring框架,可以进一步优化:
@Service
public class PaymentStrategyFactory {
@Autowired
private Map<String, PaymentStrategy> strategies;
public PaymentStrategy getStrategy(String paymentType) {
PaymentStrategy strategy = strategies.get(paymentType);
if (strategy == null) {
throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
}
return strategy;
}
}
// 策略实现类添加@Component注解
@Component("alipay")
public class AlipayStrategy implements PaymentStrategy {
// 实现
}
@Component("wechat")
public class WechatPayStrategy implements PaymentStrategy {
// 实现
}
结合枚举类型
public enum PaymentType {
ALIPAY("alipay", "支付宝支付"),
WECHAT("wechat", "微信支付"),
BANK("bank", "银行卡支付");
private String code;
private String desc;
// 构造方法、getter等
}
然后在工厂中使用枚举值作为key,提高类型安全性。
总结
工厂模式和策略模式的组合是解决条件分支过多问题的经典方案。它将选择逻辑与业务逻辑分离,使系统更加灵活、可扩展。在实际开发中,可以根据项目具体情况选择适合的实现方式,结合框架特性进一步优化。
【工厂和策略设计模式妙用】解决接口选择与多重if-else 问题的更多相关文章
- oop的三种设计模式(单例、工厂、策略)
参考网站 单例模式: 废话不多说,我们直接上代码: <?php /** 三私一公 *私有的静态属性:保存类的单例 *私有的__construct():阻止在类的外部实例化 *私有的__clone ...
- 给jdk写注释系列之jdk1.6容器(9)-Strategy设计模式之Comparable&Comparator接口
前面我们说TreeMap和TreeSet都是有顺序的集合,而顺序的维持是要靠一个比较器Comparator或者map的key实现Comparable接口. 既然说到排序,首先我们不用去关心什 ...
- java 策略设计模式
在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在 ...
- Java(Android)编程思想笔记02:组合与继承、final、策略设计模式与适配器模式、内部类、序列化控制(注意事项)
1.组合和继承之间的选择 组合和继承都允许在新的类中放置子对象,组合是显式的这样做,而继承则是隐式的做. 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形.即在新类中嵌入某个对象,让其实 ...
- Head First设计模式——策略设计模式
策略设计模式 说在前面的话 入软件一年啦,平心而论,总算不限于只会钻研些基础的语言语法了,数据结构和算法也恶补的差不多了.所以~趁着现在一边实习一边啃<Head First设计模式>的功夫 ...
- C#软件设计——小话设计模式原则之:接口隔离原则ISP
前言:有朋友问我,设计模式原则这些东西在园子里都讨论烂了,一搜一大把的资料,还花这么大力气去整这个干嘛.博主不得不承认,园子里确实很多这方面的文章,并且不乏出色的博文.博主的想法是,既然要完善知识体系 ...
- Java设计模式之策略设计模式
1.什么是-策略设计模式 在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Ha ...
- java策略设计模式
1.概述 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化. 其实不要被晦涩难懂的定义所迷惑,策略设计模式实际上就是定义一个接口,只要实现 ...
- 简单工厂模式&策略模式-简介与区别
不得不说,这两种模式真的很像. 相似点:都用到了面向对象的继承.多态.抽象,都拥有相似的结构. 不同点:工厂模式仅提供具体的实例对象,怎么使用这个对象是client的自由,策略模式client可以通过 ...
- JAVA学习笔记--策略设计模式与适配器模式
一.策略设计模式 创建一个能够根据所传递对象的不同而具有不同行为的方法被称为策略设计模式:这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分.策略就是传递进去的参数对象,它包含要执行 ...
随机推荐
- iOS Facebook和Google登录
前言 最近在对接完Google和Facebook登录之后准备对这部分内容做一个小小的总结,方便以后有需要的时候查看. 具体的Google账号申请和Facebook账号的申请在这里就不做介绍了,这部分内 ...
- eclipse安装OpenExplorer插件--快速打开文件目录
eclipse安装OpenExplorer插件--快速打开文件目录功能: 1.下载: github: 下载地址:https://github.com/samsonw/OpenExplorer/down ...
- 在 MySQL 中建索引时需要注意哪些事项?
在 MySQL 中建索引时需要注意哪些事项 索引在 MySQL 中是提升查询性能的关键,但不当的索引设计可能会导致性能下降或资源浪费.因此,在建索引时需要综合考虑性能.存储成本和业务需求. 1. 确定 ...
- 又来一个挑战 Elastic 的,初识 SigLens
Elastic Stack 在日志领域具备无与伦比的地位,各类新兴的开源项目都声称比 Elastic 更节省资源,同时检索速度也不慢,比如 ClickHouse.Loki.OpenObserve.VM ...
- win mysql实现主从同步(精简版)
最近项目要弄读写分离,那首先要实现主从同步啊,网上教程很多,但大多都看得云里雾里,so,有了这个精简版: 主库my.ini添加配置: #数据库ID号, 为1时表示为Master,其中master_id ...
- 支持命令行输入中文(例如redis-cli输入中文)
修改 cmd 控制台默认代码页编码的几种方法[GBK.UTF-8]_FKNIGHT 的博客-CSDN博客_修改cmd编码 1.进入redis-cli.exe所在文件夹 2.在路径栏输入cmd回车 3. ...
- Mysql如何给字符串添加索引(前缀索引)
在日常开发中,我们经常给字符串添加索引,那么给字段添加索引有什么技巧吗,我们看看下面的例子,我们给一个邮箱添加索引,应该如何添加呢 看看下面这条sql select * from user where ...
- RandomAccessFile、FileInputStream、MappedByteBuffer、FileChannel 区别及应用场景
RandomAccessFile.FileInputStream.MappedByteBuffer.FileChannel 比较 这些类都是Java中用于文件I/O操作的类,但各有特点和适用场景.下面 ...
- MySQL高可用之PXC
1.PXC简介 参考Percona官方https://www.percona.com/software/mysql-database/percona-xtradb-cluster PXC(Perc ...
- docker-compose 启动容器
docker-compose 是什么 docker-compose 是一个用来把 docker 自动化的东西.有了 docker-compose 你可以把所有繁复的 docker 操作全都一条命令,自 ...