前言
访问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式。是表示一个作用于某对象结构中各元素的操作,它可以在不改变各元素类的前提下定义作用于这些元素的新操作。从而把数据结构和作用于结构上的操作进行解耦合。
示例代码
前几天编写了一个关于签名的工具类SignBuilder,里面涉及到建造者模式和访问者模式两种设计模式,下面以这个案例进行说明。
访问者接口定义:/**
* Created by lipan on 2017/8/19.
* Describe: 访问者接口
*/
public interface ISignVisitor {
/**
* 生成具体的签名
* @param content
* @return
*/
String visitor(String content);
}
访问者具体实现MD5SignVisitor:/**
* Created by lipan on 2017/8/19.
* Describe: MD5签名访问者具体实现
*/
public class MD5SignVisitor implements ISignVisitor {
public String visitor(String content) {
return null;
}
}
访问者具体实现SHASignVisitor:/**
* Created by lipan on 2017/8/19.
* Describe: SHA签名访问者具体实现类
*/
public class SHASignVisitor implements ISignVisitor {
public String visitor(String content) {
return null;
}
}
具体结构对象SignBuilder:/**
* Created by lipan on 2017/8/12.
* Describle: 通用规则签名
* 具体规则如下:
* 签名生成的通用步骤如下:
* 第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2
* …)拼接成字符串stringA。
* 特别注意以下重要规则:
* ◆ 参数名ASCII码从小到大排序(字典序);
* ◆ 如果参数的值为空不参与签名;
* ◆ 参数名区分大小写;
* ◆ 验证调用返回或QQ钱包主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
public final class SignBuilder {
// 默认比较器为ASCII区分大小写的比较
private static final Comparator<String> DEFAULT_COMPARATOR = new ASCIICaseInsensitiveComparator();
// 默认分隔符
private static final String DEFAULT_SPLITE = "&";
private TreeMap<String, Object> sortMap = null;
private SignBuilder(Comparator<String> comparator) {
if(comparator == null) {
throw new IllegalArgumentException("comparator is null.");
}
this.sortMap = new TreeMap<String, Object>(comparator);
}
public static SignBuilder newBuilder() {
return new SignBuilder(DEFAULT_COMPARATOR);
}
public static SignBuilder newBuilder(Comparator<String> comparator) {
return new SignBuilder(comparator);
}
public SignBuilder put(String key, Object value) {
// 为null的值不参与签名
if(!StringUtils.hasText(key) || value == null) {
return this;
}
sortMap.put(key, value);
return this;
}
public String toSign(ISignVisitor visitor) {
StringBuilder builder = new StringBuilder();
Iterator<Map.Entry<String, Object>> iterator = sortMap.entrySet().iterator();
Map.Entry<String, Object> item;
while(iterator.hasNext()) {
item = iterator.next();
builder.append(item.getKey()).append("=").append(item.getValue()).append(DEFAULT_SPLITE);
}
String signContent = builder.toString();
signContent = signContent.substring(0, signContent.length() - DEFAULT_SPLITE.length());
// 访问者模式生成具体的签名
return visitor.visitor(signContent);
}
}
软件设计原则
开-闭原则
访问者模式将处理功能逻辑从数据结构对象中分离出来(生成具体签名的处理逻辑将来是可能变化的,除了MD5和SHA之外可能还有其他类型的签名规则),这就使得增加和修改功能变得简单,我们只需要新增或修改访问者角色即可达到目的,而不必修改数据结构对象,从而保证原有系统的稳定性,实现对系统的扩展。
单一职责原则
数据结构角色和访问者角色之间的职责分工明确,访问者角色主要负责对数据的复杂处理逻辑,而数据结构角色则负责数据的维护。各种不同类型的访问者之间(MD5SignVisitor和SHASignVisitor)实现各自的处理逻辑行为。