责任链模式(分离职责,动态组合)
2017-02-23 本文已影响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 的事件投递。