行为型模式。
目的:将数据结构 与 数据操作分离。
将对象属性的操作,交由Visitor对象进行操作。
先说明一下。
个人认为访问者模式不一定非得按照菜鸟教程的例子来写,就像单例模式有好几种实现。
我们只需要将访问者的概念实现即可。
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Computer implements ComputerPart {
private String data;
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Monitor monitor);
}
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
computer.data = "修改数据";
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
这个例子是菜鸟上的例子,已经被我简化了一下。
但是对于刚学这个模式的人来说,我感觉还是太绕了。
这个Spring里面的一个类,个人认为这个比较好理解。
下面是BeanDefinitionVisitor的代码。
为了方便理解,代码比较长的方法已经被我删了,完整代码可以自己去spring看。
public class BeanDefinitionVisitor {
@Nullable
private StringValueResolver valueResolver;
public BeanDefinitionVisitor(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
this.valueResolver = valueResolver;
}
protected BeanDefinitionVisitor() {
}
protected void visitParentName(BeanDefinition beanDefinition) {
String parentName = beanDefinition.getParentName();
if (parentName != null) {
String resolvedName = this.resolveStringValue(parentName);
if (!parentName.equals(resolvedName)) {
beanDefinition.setParentName(resolvedName);
}
}
}
protected void visitBeanClassName(BeanDefinition beanDefinition) {
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null) {
String resolvedName = this.resolveStringValue(beanClassName);
if (!beanClassName.equals(resolvedName)) {
beanDefinition.setBeanClassName(resolvedName);
}
}
}
protected void visitFactoryBeanName(BeanDefinition beanDefinition) {
String factoryBeanName = beanDefinition.getFactoryBeanName();
if (factoryBeanName != null) {
String resolvedName = this.resolveStringValue(factoryBeanName);
if (!factoryBeanName.equals(resolvedName)) {
beanDefinition.setFactoryBeanName(resolvedName);
}
}
}
protected void visitFactoryMethodName(BeanDefinition beanDefinition) {
String factoryMethodName = beanDefinition.getFactoryMethodName();
if (factoryMethodName != null) {
String resolvedName = this.resolveStringValue(factoryMethodName);
if (!factoryMethodName.equals(resolvedName)) {
beanDefinition.setFactoryMethodName(resolvedName);
}
}
}
protected void visitScope(BeanDefinition beanDefinition) {
String scope = beanDefinition.getScope();
if (scope != null) {
String resolvedScope = this.resolveStringValue(scope);
if (!scope.equals(resolvedScope)) {
beanDefinition.setScope(resolvedScope);
}
}
}
protected void visitPropertyValues(MutablePropertyValues pvs) {
PropertyValue[] pvArray = pvs.getPropertyValues();
PropertyValue[] var3 = pvArray;
int var4 = pvArray.length;
for(int var5 = 0; var5 < var4; ++var5) {
PropertyValue pv = var3[var5];
Object newVal = this.resolveValue(pv.getValue());
if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
pvs.add(pv.getName(), newVal);
}
}
}
protected void visitArray(Object[] arrayVal) {
for(int i = 0; i < arrayVal.length; ++i) {
Object elem = arrayVal[i];
Object newVal = this.resolveValue(elem);
if (!ObjectUtils.nullSafeEquals(newVal, elem)) {
arrayVal[i] = newVal;
}
}
}
protected void visitList(List listVal) {
for(int i = 0; i < listVal.size(); ++i) {
Object elem = listVal.get(i);
Object newVal = this.resolveValue(elem);
if (!ObjectUtils.nullSafeEquals(newVal, elem)) {
listVal.set(i, newVal);
}
}
}
@Nullable
protected String resolveStringValue(String strVal) {
if (this.valueResolver == null) {
throw new IllegalStateException("No StringValueResolver specified - pass a resolver object into the constructor or override the 'resolveStringValue' method");
} else {
String resolvedValue = this.valueResolver.resolveStringValue(strVal);
return strVal.equals(resolvedValue) ? strVal : resolvedValue;
}
}
}
这里就是用访问者的方法去设置BeanDefinition的属性,个人认为这个例子比较好理解。
简单粗暴,就是将数据结构和数据操作分离,BeanDefinition将设置属性的操作交给了BeanDefinitionVisitor 操作。
public class SimpleFileVisitor<T> implements FileVisitor<T> {
/**
* Initializes a new instance of this class.
*/
protected SimpleFileVisitor() {
}
/**
* Invoked for a directory before entries in the directory are visited.
*
* Unless overridden, this method returns {@link FileVisitResult#CONTINUE
* CONTINUE}.
*/
@Override
public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
throws IOException
{
Objects.requireNonNull(dir);
Objects.requireNonNull(attrs);
return FileVisitResult.CONTINUE;
}
/**
* Invoked for a file in a directory.
*
* Unless overridden, this method returns {@link FileVisitResult#CONTINUE
* CONTINUE}.
*/
@Override
public FileVisitResult visitFile(T file, BasicFileAttributes attrs)
throws IOException
{
Objects.requireNonNull(file);
Objects.requireNonNull(attrs);
return FileVisitResult.CONTINUE;
}
/**
* Invoked for a file that could not be visited.
*
* Unless overridden, this method re-throws the I/O exception that prevented
* the file from being visited.
*/
@Override
public FileVisitResult visitFileFailed(T file, IOException exc)
throws IOException
{
Objects.requireNonNull(file);
throw exc;
}
/**
* Invoked for a directory after entries in the directory, and all of their
* descendants, have been visited.
*
* Unless overridden, this method returns {@link FileVisitResult#CONTINUE
* CONTINUE} if the directory iteration completes without an I/O exception;
* otherwise this method re-throws the I/O exception that caused the iteration
* of the directory to terminate prematurely.
*/
@Override
public FileVisitResult postVisitDirectory(T dir, IOException exc)
throws IOException
{
Objects.requireNonNull(dir);
if (exc != null)
throw exc;
return FileVisitResult.CONTINUE;
}
}
创建型模式
结构型模式
行为型模式