美文网首页设计模式
责任链模式(分离职责,动态组合)

责任链模式(分离职责,动态组合)

作者: 幺鹿 | 来源:发表于2017-02-23 21:09 被阅读251次

    前言

    登录、注册功能是日常开发中必备的功能,不管哪里都有它的身影。现在需要给客户提供一个注册功能,就如下图那样。

    注册界面

    需要输入头像、姓名、邮箱地址、电话、密码这些必填项之后,才能点击注册按钮。

    假设我们已经可以正确取到每个元素(头像、姓名等)的值分解下实现过程:

    • 再点击注册按钮的时候,需要依次验证头像、姓名、邮箱地址、电话、密码这些项是否填写,是否合法。
    • 如果不合法,则提示对应的错误信息让用户尽快修改。
    • 如果合法,则最终向服务器发起注册请求。

    正文

    定义用户对象

    用于封装数据提交验证。这样我们就可以构造多个用户对象,来验证职责链模式了。

    public class User {
    
        public String name;
        public String avatar;
        public String email;
        public String phone;
        public String password;
    
        public User(String name, String avatar, String email, String phone, String password) {
            this.name = name;
            this.avatar = avatar;
            this.email = email;
            this.phone = phone;
            this.password = password;
        }
    }
    

    定义验证接口

    定义验证接口此处命名为IDuty,不同的验证可以通过实现该接口来实现。这意味着对于客户端来说,每个职责的实现类都是平等的可替代的。

    • 验证头像格式是否正确(验证标准是含有http://字符串即认为通过)
    • 验证姓名是否正确(验证标准是在4~10个字符长度)
    • 验证手机号码是否正确(验证标准是含有186字符串)
    • 验证邮箱号码是否正确(验证标准是含有@字符)
    • 验证码密码是否正确(验证标准是大于6个字符长度)
    public interface IDuty<User> {
        boolean verify(User user);
    }
    
    // 示意一个职责实现类
    public class VerifyAvatarDutyImpl extends Duty {
        @Override
        public boolean verifyImpl(User user) {
            String avatar = user.avatar;
            if (avatar == null) return false;
            else if (avatar.contains("http://"))
                return true;
            return false;
        }
    }
    

    动态组合(构成链)

    通过上述步骤,我们已经拆解了诸多验证职责。但是现有的资源,无法帮助我们构成链。

    单链表节点
    • 构造链式结构
    public abstract class Duty implements IDuty<User> {
    
        private Duty nextDuty;
        private Duty prevDuty;
    
        public Duty setNext(Duty next) {
    
            if (next == null) throw new IllegalArgumentException("duty can not be null.");
    
            Duty temp = moveToLast();
    
            temp.nextDuty = next;
            next.prevDuty = temp;
    
            return next;
        }
    
        @Override
        public final boolean verify(User user) {
            final boolean bool = verifyImpl(user);
            System.out.println("[" + getClass().getSimpleName() + "] verify :" + bool);
            if (!bool) {
                debugPrint(bool);
                return bool;
            } else {
                if (nextDuty != null) {
                    return nextDuty.verify(user);
                } else {
                    debugPrint(bool);
                    return bool;
                }
            }
        }
    
        private void debugPrint(boolean bool) {
            if (!bool)
                System.out.println("[" + getClass().getSimpleName() + "] 被迫终止");
            else
                System.out.println("[" + getClass().getSimpleName() + "] 恭喜校验通过");
        }
    
        public Duty moveToFirst() {
            Duty firstDuty = this;
            while (firstDuty.prevDuty != null) {
                firstDuty = firstDuty.prevDuty;
            }
            return firstDuty;
        }
    
        protected abstract boolean verifyImpl(User user);
    }
    
    

    客户端验证,为了避免一些书写错误。在这里直接定义了 setNext()方法,用于构造链式函数。并且提供了moveToFirst()方法,用于将指针移动到链表中的第一个元素并发起顺序调用。

      public class Client {
    
        public static void main(String[] atgs) {
    
            User user = new User("幺鹿幺鹿幺鹿", "http://www.jianshu.com", "chenjunqi.china@gmail.com", "18668247775", "1234567");
    
            new VerifyAvatarDutyImpl()
                    .setNext(new VerifyRealNameDutyImpl())
                    .setNext(new VerifyEmailDutyImpl())
                    .setNext(new VerifyPhoneDutyImpl())
                    .setNext(new VerifyPasswordDutyImpl())
                    .moveToFirst() // 为了移动到 VerifyAvatarDutyImpl 对象,然后发起顺序的链式验证
                    .verify(user);
    
        }
    }
    

    执行客户端的打印结果

    [VerifyAvatarDutyImpl] verify :true
    [VerifyRealNameDutyImpl] verify :true
    [VerifyEmailDutyImpl] verify :true
    [VerifyPhoneDutyImpl] verify :true
    [VerifyPasswordDutyImpl] verify :true
    [VerifyPasswordDutyImpl] 恭喜校验通过
    

    总结

    责任链模式本质:分离职责,动态组合。

    职责链模式.png

    番外篇

    提起职责链模式,让我就联想起 Android 的事件投递

    相关文章

      网友评论

      • 幺鹿:想找群小伙伴互相勘误彼此的文章,站在不同的角度提点建议、批判,有意向的朋友可以私信我:smile:

      本文标题:责任链模式(分离职责,动态组合)

      本文链接:https://www.haomeiwen.com/subject/lnmbwttx.html