模板方法模式:https://blog.csdn.net/dengjili/article/details/79631472
类ObjectNavigator
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Collection;
/**
* Provides ability to apply a visitor to an object and all of its fields recursively.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class ObjectNavigator {
public interface Visitor {
/**
* This is called before the object navigator starts visiting the current object
*/
void startVisitingObject(Object node);
/**
* This is called after the object navigator finishes visiting the current object
*/
void endVisitingObject(Object node);
/**
* This is called to visit the current object if it is an iterable
*
* @param componentType the type of each element of the component
*/
void visitCollection(@SuppressWarnings("unchecked") Collection collection, Type componentType);
/**
* This is called to visit the current object if it is an array
*/
void visitArray(Object array, Type componentType);
/**
* This is called to visit the current object if it is a primitive
*/
void visitPrimitiveValue(Object obj);
/**
* This is called to visit an object field of the current object
*/
void visitObjectField(Field f, Object obj);
/**
* This is called to visit a field of type Collection of the current object
*/
void visitCollectionField(Field f, Object obj);
/**
* This is called to visit an array field of the current object
*/
void visitArrayField(Field f, Object obj);
/**
* This is called to visit a primitive field of the current object
*/
void visitPrimitiveField(Field f, Object obj);
/**
* This is called to visit an enum object
*/
public void visitEnum(Object obj, Type objType);
/**
* This is called to visit an object using a custom handler
* @return true if a custom handler exists, false otherwise
*/
public boolean visitUsingCustomHandler(Object obj, Type objType);
}
private final ExclusionStrategy exclusionStrategy;
private final MemoryRefStack<Object> ancestors;
private final Object obj;
private final Type objType;
/**
* @param obj The object being navigated
* @param objType The (fully genericized) type of the object being navigated
* @param exclusionStrategy the concrete strategy object to be used to
* filter out fields of an object.
*/
ObjectNavigator(Object obj, Type objType, ExclusionStrategy exclusionStrategy,
MemoryRefStack<Object> ancestors) {
Preconditions.checkNotNull(exclusionStrategy);
Preconditions.checkNotNull(ancestors);
this.obj = obj;
this.objType = objType;
this.exclusionStrategy = exclusionStrategy;
this.ancestors = ancestors;
}
/**
* Navigate all the fields of the specified object.
* If a field is null, it does not get visited.
*/
@SuppressWarnings("unchecked")
public void accept(Visitor visitor) {
if (obj == null) {
return;
}
TypeInfo<?> objTypeInfo = new TypeInfo<Object>(objType);
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getTopLevelClass())) {
return;
}
if (ancestors.contains(obj)) {
throw new IllegalStateException("Circular reference found: " + obj);
}
ancestors.push(obj);
try {
if (isCollectionOrArray(objTypeInfo)) {
if (objTypeInfo.isArray()) {
visitor.visitArray(obj, objType);
} else { // must be a collection
visitor.visitCollection((Collection<?>)obj, objType);
}
} else if (objTypeInfo.getTopLevelClass().isEnum()) {
visitor.visitEnum(obj, objType);
} else if (objTypeInfo.isPrimitiveOrStringAndNotAnArray()) {
visitor.visitPrimitiveValue(obj);
} else {
if (!visitor.visitUsingCustomHandler(obj, objType)) {
visitor.startVisitingObject(obj);
// For all classes in the inheritance hierarchy (including the current class),
// visit all fields
for (Class<?> curr = objTypeInfo.getTopLevelClass();
curr != null && !curr.equals(Object.class); curr = curr.getSuperclass()) {
if (!curr.isSynthetic()) {
navigateClassFields(obj, curr, visitor);
}
}
visitor.endVisitingObject(obj);
}
}
} finally {
ancestors.pop();
}
}
private void navigateClassFields(Object obj, Class<?> clazz, Visitor visitor) {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) {
TypeInfo<?> fieldTypeInfo = new TypeInfo<Object>(f.getType());
if (exclusionStrategy.shouldSkipField(f)) {
continue; // skip
} else if (isCollectionOrArray(fieldTypeInfo)) {
if (fieldTypeInfo.isArray()) {
visitor.visitArrayField(f, obj);
} else { // must be Collection
visitor.visitCollectionField(f, obj);
}
} else if (fieldTypeInfo.isPrimitiveOrStringAndNotAnArray()) {
visitor.visitPrimitiveField(f, obj);
} else {
visitor.visitObjectField(f, obj);
}
}
}
private static boolean isCollectionOrArray(TypeInfo<?> typeInfo) {
return Collection.class.isAssignableFrom(typeInfo.getTopLevelClass()) || typeInfo.isArray();
}
@SuppressWarnings("unchecked")
private static final Class[] PRIMITIVE_TYPES = { int.class, long.class, short.class, float.class,
double.class, byte.class, boolean.class, Integer.class, Long.class, Short.class, Float.class,
Double.class, Byte.class, Boolean.class };
@SuppressWarnings("unchecked")
static boolean isPrimitiveOrString(Object target) {
if (target instanceof String) {
return true;
}
Class<?> classOfPrimitive = target.getClass();
for (Class standardPrimitive : PRIMITIVE_TYPES) {
if (standardPrimitive.isAssignableFrom(classOfPrimitive)) {
return true;
}
}
return false;
}
}
代码解析
定义内部接口
定义模板方法,直接调用定义的接口方法
子类实现这个接口,到达模板方法的目的,将细节延迟到子类
优点
这种方式是通过组合方式,达到目的,而模板方法模式是通过继承方式