java - Dynamically choose method at runtime; alternatives to Visitor Pattern or Reflection -


i'm working on small game template, world comprised of nodes so:

world |--zone |----cell |------actor |------actor |--------item 

where world can contain multiple zone objects, zone can contain multiple cell objects, , on.

each of these implements node interface, has few methods getparent, getchildren, update, reset , on.

i want able execute given task on single node or recursively down tree node (as specified task).

to compound issue, "pluggable" system, meaning want players/developers able add new types tree on fly. had considered casting base types:

public void dotask(actor node) {     if(!(node instanceof goblin)) { return; }     goblin goblin = (goblin) node; } 

initially drawn use visitor pattern take advantage of double dispatch, allowing each routine (visitor) act according type of node being visited. however, caused few complications, when want add new node type tree.

as alternative, wrote utility class uses reflection find specific method applicable node.

my concern performance; since there large number of reflective lookups , calls, i'm worried performance of game (which have hundreds or thousands of these calls per second) suffer.

which seems solve problem of both patterns, makes code each new task uglier.

the way see it, have 3 options allowing dynamic dispatch (unless i'm missing obvious/obscure, why i'm here):

  1. visitor pattern
    • pros
      • double dispatch
      • performance
      • clean code in tasks
    • cons
      • difficult add new node types (impossible without modifying original code)
      • ugly code during invocation of tasks
  2. dynamic invocation using reflection
    • pros
      • can add new node types abandon
      • very customizable tasks
      • clean code in tasks
    • cons
      • poor performance
      • ugly code during invocation of tasks
  3. casting
    • pros
      • more performant reflection
      • potentially more dynamic visitor
      • clean code during invocation of tasks
    • cons
      • code smell
      • less performant visitor (no double dispatch, casting in each invocation)
      • ugly code in tasks

have missed obvious here? i'm familiar many of gang of 4 patterns, ones in game programming patterns. appreciated here.

to clear, i'm not asking of these "best". i'm looking alternative these approaches.

i think if cannot have static factory class tough problem. if static factory allowed, perhaps short example might provide ideas.

this sort of approach allows run-time insertion of inode instances tree (worldnode), however, doesn't answer how these concrete inodes created. hope have kind of factory pattern.

    import java.util.vector;      public class world {        public static void main(string[] args) {         inode worldnode = new worldnode();         inode zonenode = new zonenode();          zonenode.addnode(new goblinnode());         zonenode.addnode(new goblinnode());         zonenode.addnode(new goblinnode());         zonenode.addnode(new goblinnode());         worldnode.addnode(zonenode);          worldnode.addnode(new zonenode());         worldnode.addnode(new zonenode());         worldnode.addnode(new zonenode());          worldnode.runtasks(null);       }     }      interface inode {       public void addnode(inode node);       public void addtask(itask node);       public vector<itask> gettasks();       public void runtasks(inode parent);       public vector<inode> getnodes();     }      interface itask {       public void execute();     }      abstract class node implements inode {       private vector<inode> nodes = new vector<inode>();       private vector<itask> tasks = new vector<itask>();        public void addnode(inode node) {         nodes.add(node);       }        public void addtask(itask task) {         tasks.add(task);       }        public vector<itask> gettasks() {         return tasks;       }        public vector<inode> getnodes() {         return nodes;       }        public void runtasks(inode parent) {         for(itask task : tasks) {           task.execute();         }         for(inode node : nodes){           node.runtasks(this);         }       }     }      class worldnode extends node {       public worldnode() {         addtask(new worldtask());       }     }      class worldtask implements itask {       @override       public void execute() {         system.out.println("world task");       }     }      class zonenode extends node {       public zonenode() {         addtask(new zonetask());       }     }      class zonetask implements itask {        @override       public void execute() {         system.out.println("zone task");       }     }      class goblinnode extends node {       public goblinnode() {         addtask(new goblintask());       }     }      class goblintask implements itask {        @override       public void execute() {         system.out.println("goblin task");       }     } 

output:

world task     zone task         goblin task         goblin task         goblin task         goblin task zone task zone task zone task 

Comments