Java 根据类型层次结构进行匹配
假设我们有一个固定的类型层次结构,如下图所示。它是一个定义良好的树,其中每个节点都有一个父节点(根节点除外) 每个类型都有一个与之关联的操作,该操作应在成功匹配后执行。这并不意味着动作对应于所述类型的方法。这只是随意的联想 根据类型层次结构匹配对象的智能方法有哪些?Java 根据类型层次结构进行匹配,java,design-patterns,types,casting,hierarchy,Java,Design Patterns,Types,Casting,Hierarchy,假设我们有一个固定的类型层次结构,如下图所示。它是一个定义良好的树,其中每个节点都有一个父节点(根节点除外) 每个类型都有一个与之关联的操作,该操作应在成功匹配后执行。这并不意味着动作对应于所述类型的方法。这只是随意的联想 根据类型层次结构匹配对象的智能方法有哪些? 每个对象都应该与可能的最特定类型相匹配。对象已创建。从根目录使用递归搜索 一旦在子对象中找不到匹配项,请记住匹配的对象(如果其级别比上一个匹配项更深) 伪代码: class MatchContext {
每个对象都应该与可能的最特定类型相匹配。对象已创建。从根目录使用递归搜索 一旦在子对象中找不到匹配项,请记住匹配的对象(如果其级别比上一个匹配项更深) 伪代码:
class MatchContext {
public int level;
public Node result;
}
public boolean match(Node object, int level, MatchContext ctx) {
if (no match)
return false;
boolean found = false;
for (all children in object) {
if (match(child, level + 1, ctx))
found = true;
}
if (!found && level > ctx.level) {
ctx.level = level;
ctx.result = this;
}
return found;
}
像这样调用它:
MatchContext ctx;
if (match(root, 0, ctx))
myAction(ctx.result);
树层次结构已经由类的声明隐式定义。您只需要通过chained
getSuperclass()
调用要查找的类型来遍历一个树分支。然后,可以使用简单的哈希映射来组织树节点(类类型)
如果类型层次结构是静态的,可以将其定义为enum
public enum ClassType{
HOMINOIDEA(HOMINOIDEA.class),
HOMINIDAE(HOMINIDAE.class),
HOMININAE(HOMININAE.class),
//and so on
UNKNOWN(null);
private static final Map<Class<?>, ClassType> typesMap = new HashMap<>();
public final Class<?> type;
static{
for (ClassType classType : EnumSet.allOf(ClassType.class)){
if(classType.type != null){
typesMap.put(classType.type, classType);
}
}
}
private ClassType(Class<?> type){
this.type = type;
}
public static ClassType getClassTypeOf(Class<?> type){
for(Class<?> lookupType = type; lookupType != null; lookupType = lookupType.getSuperclass()){
ClassType classType = typesMap.get(lookupType);
if(classType != null){
return classType;
}
}
return UNKNOWN;
}
}
我想到的解决方案是遍历类型和关联操作的元组树。是否要检查给定对象的类型?你能给我们举个代码示例吗?我不太明白。如果您有属于上述类/类型层次结构的对象,以及表示操作的方法,那么对这些对象调用这些方法将自动调用最具体的操作。我无法更改对象,因此无法利用多态性。我想用外部接口对外部对象进行分类。您可以控制对象的实例化吗?如果是这样,你可以使用适配器。我的直觉也是一棵树。这将产生O(logn)与max匹配。最后一个if条件中存在错误。为了在根级别上获得匹配,您需要将
ctx.level==0&&level==0
和level
与逻辑or结合起来。还考虑了散列,但is有一个缺陷,您尝试在第二种方法中解决该缺陷。散列将丢失类型之间的层次关系。第二种方法还有一个次要的流程,因为它不区分类型(或接口)和实际类。一个类可以实现不同的接口,这将破坏树,因为节点的父节点将不再被很好地定义。@mike也在第一种方法中进行超类查找-在getClassTypeOf()
中。我认为给定了一个定义良好的类型层次结构,您希望与这个给定的层次结构相匹配。给定的定义良好的树如何被“销毁”?但是,这两种方法都应该适用于在查找函数中使用getInterfaces()
的接口。啊,对不起,我的错误。与类型相关:类型和类之间存在差异。或者用Java术语来描述接口和类。是的,您的解决方案可以工作,但是@RustyX的解决方案更稳定,因为它对实际的实现类是不变的。
public static void main(String[] args){
EnumMap<ClassType, Action> actionMap = new EnumMap<>(ClassType.class);
actionMap.put(ClassType.HOMININAE, new HomininaeAction());
Homininae h = new Homininae();
actionMap.get(ClassType.getClassTypeOf(h)); //action associated with homininaes
}
public class ActionDispatcher {
private final Map<Class<?>, Consumer<?>> actionMap = new HashMap<>();
public <T> void registerAction(Class<T> type, Consumer<? super T> action){
actionMap.put(type, action);
}
@SuppressWarnings("unchecked")
public void dispatchActionFor(Object object){
Consumer<Object> action = ((Consumer<Object>)getActionFor(object.getClass()));
if(action != null){
action.accept(object);
}
}
private Consumer<?> getActionFor(Class<?> type){
for(Class<?> lookupType = type; lookupType != null; lookupType = lookupType.getSuperclass()){
Consumer<?> action = actionMap.get(lookupType);
if(action != null){
return action;
}
}
return null;
}
//demo
public static void main(String[] args){
ActionDispatcher dispatcher = new ActionDispatcher();
dispatcher.registerAction(Number.class, n -> System.out.println("number: " + n));
dispatcher.registerAction(Double.class, d -> System.out.println("double: " + d));
dispatcher.registerAction(String.class, s -> System.out.println("first char: " + s.charAt(0)));
dispatcher.registerAction(Object.class, o -> System.out.println("object: " + o));
dispatcher.dispatchActionFor(new Integer(3));
dispatcher.dispatchActionFor(new Double(3.0));
dispatcher.dispatchActionFor("string");
dispatcher.dispatchActionFor(new Thread());
}
}