2017-02-02 18 views
4

Предположим, что мы имеем иерархию фиксированного типа, например. как показано ниже. Это хорошо определенное дерево, где каждый узел имеет один родительский элемент (кроме корня).Соответствие иерархии типов

Human taxonomy

Каждый тип имеет действие, связанное с ним, которые должны быть выполнены после успешного согласования. Это делает не означает, что действие соответствует методу указанного типа. Это просто произвольная ассоциация.

Каковы интеллектуальные способы сопоставления объектов с иерархией типов? Каждый объект должен быть сопоставлен с наиболее конкретным типом. Объекты уже созданы.

+0

Решение, которое я имею в виду обходе дерева кортежей типа и связанных с ними действий. – mike

+0

Вы хотите проверить тип данного объекта? Можете ли вы привести пример кода? –

+2

Не уверен, что я понимаю. Если у вас есть объекты, принадлежащие к вышеуказанной иерархии классов/типов, и методы, представляющие действия, то вызов этих методов на объектах будет автоматически вызывать наиболее конкретное действие. – user152468

ответ

1

Используйте рекурсивный поиск из корня.

Как только не найдено ни одного совпадения в дочерних элементах, помните соответствующий объект, если его уровень глубже последнего совпадения.

псевдокод:

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; 
    } 

Invoke это следующим образом:

MatchContext ctx; 
    if (match(root, 0, ctx)) 
     myAction(ctx.result); 
+0

Моя интуиция была также деревом. Это дает O (log n) соответствует макс. – mike

+0

В последнем условии if есть ошибка. Чтобы получить совпадения на корневом уровне, вы должны комбинировать 'ctx.level == 0 && level == 0' и' level mike

0

Дерево иерархии уже неявно определяется объявлением классов. Вам просто нужно пересечь одну ветвь дерева через цепочку getSuperclass() вызовов типа, который вы хотите найти. Затем узлы дерева (типы классов) могут быть организованы с использованием простой хэш-карты.

Учитывая, что иерархия типов является статическим, вы можете определить его как перечисление

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; 
    } 
} 

, а затем сопоставить типы классов к действиям:

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()); 
    } 

} 

Выход этого:

number: 3 
double: 3.0 
first char: s 
object: Thread[Thread-0,5,main] 
+0

Также подумал о хэшировании, но есть недостаток, который вы пытались решить в своем втором подходе. Хеширование теряет иерархическую взаимосвязь между типами. Второй подход также имеет незначительный поток, поскольку он не различает типы (или интерфейсы) и фактические классы. Класс мог реализовывать различные интерфейсы, это уничтожило бы дерево, поскольку родитель узла не был бы точно определен. – mike

+0

@mike Также в первом подходе происходит суперкласс-lookup - в 'getClassTypeOf()'. Я думал, что существует четко определенная иерархия типов, и вы хотите соответствовать этой заданной иерархии. Как можно «уничтожить» данное четко определенное дерево? Однако оба подхода должны быть адаптированы к наличию интерфейсов с использованием 'getInterfaces()' в функциях поиска. – Calculator

+0

Ах, извините, моя ошибка. В отношении типов: существует разница между типами и классами. Или в Java термины интерфейсы и классы. Да, ваше решение будет работать **, но ** решение @RustyX более стабильно, поскольку оно инвариантно к фактическим классам реализации. – mike

 Смежные вопросы

  • Нет связанных вопросов^_^