设计模式在实际中的应用---责任链/适配器

设计模式在实际中的应用—责任链/适配器

一 何为责任链模式/适配器模式?

这类定义很多人都写了,这里不赘述,放上我随便找的链接:

Carson带你学设计模式:适配器模式(Adapter Pattern) - 简书 (jianshu.com)

【设计模式】之责任链模式 - 简书 (jianshu.com)

简单总结一下我对这两种设计模式的理解:

1 责任链模式,需要有一个指向下一个bean的指针或成员变量,在当前方法执行到某个条件判断时,就会调用下一个bean的方法;构建好责任链后,只需调用一个链的一个bean的方法,就会按情况自动执行后续链;

2 适配器模式:加入A,B,C,D四个bean都是处理日志的组件,但是其提供的接口名、入参、出参可能都不一样,如何用一个接口统筹所有组件的相同功能? -----》适配器模式;

二 实际应用实例-----邮件/短信发送功能

1 业务分析

现在很多app都需要给用户发送邮件/短信,场景包括:

登录验证码、修改密码、推送广告等等,谁还不是个每天都被推送骚扰的打工人呢?

所以一个app,肯定会需要对接国内外的邮件、短信服务商;

而且不能只有一家,万一他家更新服务,或者网络波动等等,自己app的发送功能必然收到影响,邮件、短信系统的可靠性就降低了;

同时,你需要知道自己的消息是不是发成功了,如果失败了,在某些场景下,比如交易时,那么就需要重新发送了。因此这个系统还需要可以获取发送结果;

总结一下:

1 需要对接多家服务商;

2 需要获取发送结果;

简单分析下,不难得出:

多家服务商保证可靠性----》责任链;

获取结果----》适配器模式

2 代码示例:

这里以邮件为例。

首先,定义邮件接口:

public interface EmailComponent {

    /**
     * 获取发送邮件结果
     *
     * @param emailId 各服务平台邮件唯一标识ID
     * @return 邮件发送结果
     */
    SendResult getSendResult(String emailId);
    
    /**
     * 发送文本邮件
     * @param dto 发送文本邮件dto
     */
    void sendTextEmail(TextEmailDTO dto);

    /**
     * 构建责任链, 用于重试失败自动选择其他服务商
     *
     * @param component 邮件组件
     */
    void setNextProvider(TextEmailComponent component);
}

public class TextEmailDTO {
    /**
     * 接收人
     */
    private String receiver;

    /**
     * 消息内容
     */
    private String content;

    /**
     * 邮件标题/摘要
     */
    private String subject;
}

服务商A:

public class A implements EmailComponent{
	/**
	 * 下一个提供商
	 */
	private EmailComponent nextProvider;
	@Override
	public void sendTextEmail(TextEmailDTO dto){
		Boolean sendResult = doSendEmail(dto);
		if(sendResult) {
			record();  //插入记录
		}else {
			nextProvider.sendTextEmail(dto);
		}
	}
	
	@Override
    public void setNextProvider(TextEmailComponent component) {
            this.nextEmailComponent = component;	//用于构建责任链
    }
    
    @Override
    public SendResult getSendResult(String emailId) {
        SendResultOfA resultOfA = getSendResultOfA(emailId);  //每个服务上返回的结果都是不一样的;如果用了服务B,这里就会是SendResultOfB
        return constructSendResult(resultOfA);	//构造统一的返回对象
    }
    
    private SendResult constructSendResult(MailGunSendResult mailGunResult) {
        ......	//针对不同厂商,方法内容不同
    }
}

从服务A的代码可以看出:

用成员变量nextProvider 来指向下一个服务商,完成责任链的调用;

用 getSendResult(String emailId) 方法,将不同的厂商获取发送结果的方法统一,调用者只需要调用 getSendResult(String emailId) 方法即可,无须再知道每个厂商的具体实现细节,即可获取到发送结果;

责任链如何构建,这里给个思路:

1 先在spring容器中拿到所有服务商bean,然后根据想要的顺序排序后存入list中;

2 将list(0)的下一个服务商设置为list(1), 以此类推;

3 注意:当list索引为list.size()-1 时,已经是责任链的末尾了,此时需要将该服务商的下级服务商设置为null;否则,当再次构建服务商责任链时,可能会形成一个环。比如A->B->C,即A服务商最先被调用,失败则调用B,以此类推;此时你想把顺序换为A, C, B, 即A->C->B, 此时,若不设置B的下级为null,由于顺序改变前B指向C, 那么改变后,就变成了A->C->B->C->B…一直BC循环;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值