此时有一个场景,须要设计一个根据不一样的状态和条件采用不一样的业务处理方式。java
这样你们可能不是太理解。举个例子,如今大街小巷上的商户都采用了聚合支付的支付方式,聚合支付也就是商户柜台前放了一个支持支付宝、微信、京东钱包、银联等等的二维码,用户能够经过任意一款支付APP进行支付。git
对每一个支付渠道进行定义枚举类型github
public enum PayWay {
ALI_PAY,
WECHAT_PAY;
}
复制代码
而后在每一个对应的service上定义注解,表示对应哪一种支付方式spring
@Pay(PayWay.ALI_PAY)
public class AliPayServiceImpl implements PayService {}
复制代码
可是仔细思考后,仍是存在一些问题springboot
PayWay
这个枚举类型if else
判断PayWay
,增长支付方式仍是得修改原有的判断逻辑。伪代码以下if("xxx" == "aliPay"){
} else if("xxx" == "wechatPay"){
}
//若是增长支付方式仍是得增长else if
复制代码
在思路①中存在一些问题,首当其冲的就是if else
判断问题。先思考一下这个if else
的做用是什么?bash
答:根据思路①描述,这个if else
是用来肯定采用哪一种支付方式。微信
咱们能够将这块代码抽离出来,让对应的业务实现类实现本身的逻辑实现,而后根据返回值true
或者false
决定是否过滤掉这个业务实现类。接口定义以下,SupportBean
是封装的一个实体框架
boolean isSupport(SupportBean supportBean);
复制代码
而后在各个业务实现类都实现本身的isSupport方法,伪代码以下ide
@Override
public boolean isSupport(SupportBean supportBean) {
if (supportBean.getType() == "xxx"){
return true;
}
return false;
}
复制代码
注:只提供一个架子工具
Service接口定义,一个业务执行方法execute(参数自行添加),一个isSupport方法(返回true
或者false
)
public interface Service {
void execute();
boolean isSupport(SupportBean supportBean);
}
复制代码
这里execute方法只是在控制台打印字符串。isSupport方法对SupportBean中的supportNum进行取余,判断余数是否等于0,是则返回true。
相似的实现还有两个,这里就不贴出来了。
@Component
public class AServiceImpl implements Service {
@Override
public void execute() {
System.out.println("A execute");
}
@Override
public boolean isSupport(SupportBean supportBean) {
return supportBean.getSupportNum() % 3 == 0;
}
}
复制代码
接下来在定义一个帮助类
@Component
public class Helper {
@Autowired
private List<Service> services;
public void execute(SupportBean supportBean){
Service s = services.stream()
.filter((service) -> service.isSupport(supportBean))
.findFirst()//NPE异常
.orElse(null);
if (s != null){
s.execute();
}
}
}
复制代码
经过工具类的execute方法来获取对应的业务实现类执行的结果,以及对传入的参数进行校验处理等。
须要注意的是Lambda表达式的findFirst()会出现NullPointException异常。由于filter对list进行过滤,会存在过滤完list的长度为0,若是此时在调用findFirst则会抛出NullPointException。能够将上面的代码修改成以下代码,这样就能够避免NPE了
Service s = services.stream()
.filter((service) -> service.isSupport(supportBean))
.map(Optional::ofNullable)
.findFirst()
.flatMap(Function.identity())
.orElse(null);
复制代码
添加一个springboot测试类和一个测试方法。
在contextLoads测试中调用帮助类Helper的execute方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Autowired
private Helper Helper;
@Test
public void contextLoads() {
Helper.execute(new SupportBean(3));
}
}
复制代码
测试结果
A execute
复制代码
在Lambda表达式中是先将业务实现类进行过滤,而后获取第一个业务实现类并执行。
若是此时过滤存在多个业务实现类,而又不能肯定优先级,这时须要如何进行扩展呢?
其实很简单,先在Service接口中定义一个getPriority
方法
int getPriority();
复制代码
而后各自的实现类实现对应的getPriority
方法
接着修改Lambda表达式便可,在filter后增长sorted方法便可对业务实现类进行排序
Service s = services.stream()
.filter((service) -> service.isSupport(supportBean))
.sorted(Comparator.comparing(Service::getPriority))
.map(Optional::ofNullable)
.findFirst()
.flatMap(Function.identity())
.orElse(null);
复制代码
整个大致框架基本都搭建完成,如需扩展只须要增长对应的业务实现类,而不用去修改其余类的代码。就连以前设计的枚举均可以不用,可扩展性大大提高。如需使用,只需修改对应的入参和对应的名称便可。 Github地址 若是对你有收获,欢迎star、欢迎fork 若是你也有相似的经验,欢迎加入,一块儿共建