Dynamically adapt program behavior at runtime Imagine you are creating a game that contains many different classes of things; there are players, monsters, and objects that can be picked up. In addition, magic spells can change the classification of things for a set time period. A monster might transform into an object that can be carried, or an object might pick itself up and walk around like a monster.Implementing this sort of arrangement with a traditional inheritance hierarchy and data-driven attributes is a difficult housekeeping task, as things must transform back to their initial characteristics as soon as the spell ends or is dispelled. If every new spell implementation required the developer to modify all of the methods of the game’s physics model to check for the existence of each enchantment, the application would quickly become unmaintainable. It would also prove difficult to find all of the source code associated with any existing spell, as said code would be scattered throughout the application. A better paradigm is needed that allows the common effects of each spell to exist together in one class that can be used to change the effect of many diverse methods throughout the application.Dynamic Behaviors, a design pattern similar to the Chain of Responsibility pattern, is ideally suited for applications that must change the class of objects fluidly at runtime. MacApp 3.0 used behaviors to implement dynamic “adorners” that could be used to change the way objects in the user interface were drawn. The C++ implementation relied on multiple inheritance and pointer fields inside the behavior objects themselves. This article presents a more flexible alternative that allows the same behavior to modify multiple objects without relying on multiple inheritance or other features unavailable in Java. This implementation’s design puts a high premium on the simplicity of defining new behavior classes; applications that need behaviors may require numerous classes, so they should be as easy as possible to write.Flow of control in behaviorsJava is not a dynamic language; to simulate a dynamic language’s features in Java, you must add a certain amount of “glue” to each class method that may be modified by appending behaviors to that class’s object instance. To do this, first split method foo() into two methods: foo() and fooDefaultBehavior(). foo() is called the dispatch method and fooDefaultBehavior() is the default behavior method (naturally enough).Figure 1 shows the flow of control involved. When a caller invokes the method foo(), conceptually, she expects to execute the code in the default behavior method. If behaviors are attached to the object, though, they are each allowed to override foo()‘s behavior; they are able to perform different operations, invoke the default behavior, and modify the returned result. Figure 1. Dynamic Behavior flow of controlThe foo() method first creates a behavior iterator and then dispatches to the first object in the behavior chain. The objects in the behavior chain contain methods that all take the behavior iterator as their first parameter and use it to obtain a reference to the next behavior in the call chain. When the foo() method creates the iterator via getInheritanceChain, it initializes the iterator such that fooDefaultBehavior() is the last behavior in the chain. There is always a terminating default behavior, even if it does nothing. Behavior objects can rely on this invariant and always call the next behavior without checking for null pointers, which simplifies the code.The magic in the Dynamic Behaviors pattern lies in the implementation of the behavior iterator. The use pattern employed in each method is relatively simple, which is a highly desirable characteristic of a pattern that will be employed frequently in applications that use it.Using and defining behaviorsThis section describes those requirements for making a method that can be modified by Dynamic Behaviors and for defining a Java object that can be used as a behavior. Special capabilities of full-class behaviors (as explained below) are also described. Set up your projectThe behaviors distribution comes with everything you need to use behaviors in your project; see Resources for the download link. Add all of the .jar files in the lib directory to your CLASSPATH, and put the bin directory in your PATH environment variable.If you’d like to rebuild the project, just use the make clean all test-all command and the .jar file and Javadocs will regenerate. (Someday I’ll make an Ant build.xml file.) There are two test directories: one called test and the other called test-withgenerator. The latter uses the code generator, whereas the former uses handwritten dispatch code. Both techniques are described below.Requirement for dynamic behavior use in JavaThe requirements for classes that use behaviors are minimal. A BehaviorList that contains the object’s behaviors must be maintained. The behavior list is used as follows: Listing 1. Dynamic behavior dispatch example public int foo(int value) { Iterator chain = fBehaviorList.getInheritanceChain(FooInterface.class, new FooInterface() { public int foo(Iterator chain, int value) { return fooDefaultBehavior(value); } } ); return ((FooInterface) chain.next()).foo(chain, value); } public int fooDefaultBehavior(int value) { return value + 17; } FooInterface must be defined, of course. Usually, the most convenient way is to declare the interface inside the class that has the behavior dispatch method, naming the interface after the behavior method it implements, and defining but one method per behavior interface. External clients would then refer to FooInterface as MyClass.FooInterface. Of course, you may also define FooInterface in FooInterface.java, but, if you follow this route, beware of an explosion of interface files in an application that uses behaviors extensively.If the behavior dispatch code looks a bit confusing, not to worry—a useful code generator can keep your class simple and still allow the use of Dynamic Behaviors. Skip ahead to Listing 2 if you don’t care how the dynamic behavior dispatch mechanism works. Note in Listing 1 the use of anonymous classes in the dispatch method. This allows for the easy creation of new behavior classes. Note also that the behavior iterator’s first parameter is always the class object of the behavior interface being iterated. This additional magic simplifies behavior dispatching, as the behavior iterator skips any behavior in the chain that does not implement the named interface. The anonymous class implementation, also provided to the behavior iterator as its second parameter, is required, even if the method’s default behavior does nothing. This constraint ensures that a terminating object is always at the end of the behavior chain, an invariant that simplifies the code in each behavior class (as described below).After the iterator of behavior interfaces is obtained, we use it to acquire a reference to the first matching interface in the list with chain.next(), typecast it to FooInterface (which is guaranteed to always work), and call the appropriate method of the first behavior found. If no behaviors are associated with the specified interface in the behavior list, then the behavior inheritance chain iterator will return the anonymous class instance created on the previous line, which does nothing but call the default behavior function below.You might think that the above pattern could be simplified by moving the implementation of fooDefaultBehavior() inside the anonymous new FooInterface(); however, doing so is not recommended. Keeping the behavior dispatch method separate from the default behavior makes the code easier to read. Once you understand the pattern, there is no need to read the dispatch method, as all of the logic appears in the default behavior. You can keep the redundant dispatch methods out of your code completely if you use a code generator to create them for you. To do so, insert some special directives in your Javadoc comment sections similar to those used in XDoclet (see Resources). An example is shown in Listing 2.Listing 2. Build the dispatch method with a code generator /** * @INgen.behaviordispatch * behaviorList="fBehaviorList" * behaviorInterface="FooInterface" * behaviorMethod="foo" */ public int foo(int value) { return value + 17; } XDoclet is an extremely useful, easily extensible code generator, but it does not support the insertion of the generated code back into the original source file, so it is not useful for our purposes. Instead, we use a similar but much simpler code generator called INgen that does insert the generated code directly in the Java source stream that it was created from. If we wanted to depend on J2SE 5, we could use the annotation processing tool to build an annotation-based generator (and someday will); however, the provided solution works with J2SE 1.4 and amounts to only about a page of code. INgen looks for the directive @INgen.behaviordispatch (case-sensitive) in Javadoc comments that come immediately before method declarations in your Java source code. INgen is an extremely simple and limited code generator with several restrictions on its use. Javadoc sections must begin on lines that contain only white space before the /** start marker, and nothing may appear in the source code between the end of the comment section and the method declaration it modifies.After the behaviordispatch directive, INgen expects to find three parameters. The parameter behaviorList contains the name of the BehaviorList variable that contains the behavior objects that will override this method. The parameter behaviorInterface names the interface that behavior objects must implement to be called by this method’s behavior dispatch code. Finally, the parameter behaviorMethod names the method of that interface to be called. The behavior method parameter is optional; if omitted, its value defaults to the method name being modified. Parameter keywords are case-insensitive, but their values are case-sensitive, since they are inserted directly into the generated source code.INgen uses these parameters to produce the dispatch code shown in Listing 1. The method being modified is renamed from foo() to fooDefaultBehavior(), and a new foo() method containing the behavior dispatcher is inserted in the code ahead of it. To use INgen in your project, run the code generator with a command similar to the following: ingen src/packagepath/MyCode.java > objects/generated-src/packagepath/MyCode.java To use INgen, you must be sure to put behaviors.jar on your CLASSPATH, because the code generator .class file is packaged there. Of course, you must also modify your build rules to compile the Java code in objects/generated-src instead of in src. Doing this complicates your build file a bit, but the benefit is simplified Java source code—a good trade off. If you’d rather not introduce the code generator into your build process, you can always add the Behavior Dispatch pattern from Listing 1 directly to every method you’d like to override. That will be more work in the long run, though.Requirement for new behavior objectsIn short, behavior objects have no requirements, other than their implementation of an interface that contains a method (or methods) with the correct parameters, as shown in the previous section. “Correct” parameters means that the behavior method should take an iterator as its first parameter, and the subsequent parameters should match those in the behavior dispatch method. The behavior’s implementation should call the iterator’s next() method (again, as shown above) to invoke the default behavior of the function being modified. Code can be added before and after the point where the inherited functionality is called. Although not required, it is useful if a behavior extends the class Behavior. Doing this gives each behavior object additional functionality beneficial to implementing the kinds of functions that applications using behaviors typically need. I describe the provided functionality in the sections below.Listing 3 shows an example behavior called DoublingBehavior that doubles the result returned from the method foo(int) in any object it is attached to:Listing 3. A simple behavior class DoublingBehavior extends Behavior implements FooInterface { DoublingBehavior() {} public int foo(Iterator chain, int value) { int inheritedResult = ((FooInterface) chain.next() ).foo(chain, value); return inheritedResult * 2; } } To be a full-class behavior, a class should extend Behavior and implement the behavior interface used by the method it will override. It is possible to make a single object that implements multiple behavior interfaces; if this is done, the behavior will be called any time any of the associated methods of the object it is attached to are invoked. Note in Listing 3 how the code that determines the inherited result uses the behavior chain iterator to call the inherited function. The behavior chain iterator is guaranteed to always return an object of the appropriate interface (as specified by its constructor, as called in the dispatch method; see Listings 1 and 2). If no further behaviors are in the chain, the chain iterator will return a behavior object that calls the default behavior method of the object this behavior is attached to.If a behavior object cannot extend Behavior due to a requirement to extend another base class, the behavior object may instead implement the interface IBehavior. Each IBehavior method has trivial implementations that involve calling a corresponding static method in the Behavior class. Consult the source file Behavior.java and IBehavior.java if you need to do this.Dynamically change application behaviorOnce you have class methods with behavior dispatch code and behavior objects to use with them, dynamically changing an application’s behavior is easy. You only need to define public access methods for your class’s behavior list, as shown in the code below. Listing 4. Dynamically change application behavior class DynamiclyExtendableClass { BehaviorList fBehaviorList; public void addBehavior(Object behavior) { fBehaviorList.add(behavior); } public void removeBehavior(Object behavior) { fBehaviorList.remove(behavior); } } Other code in your application that wishes to change a given object’s behavior may create behaviors and use the provided addBehavior()/removeBehavior() methods as needed. If the behavior objects used extend the Behavior class, then other capabilities are also available, as described in the following section.Special capabilities of behavior objectsFull-class behavior objects (those that extend the Behavior class and/or implement the ActiveSubBehaviors interface) have special capabilities that clients may rely on. These capabilities include: The ability to find the behavior’s parent objectThe ability to remove the behavior from all of the behavior’s parent objectsThe ability to treat sub-behaviors attached to this behavior as if they were attached to the behavior’s parent object (for each parent individually) without actually inserting them in each of the parent’s behavior listsAccess parent objectsBehaviors can be attached to multiple objects. The behavior method has access to all of the parent objects it is attached to, which can prove useful when employing behavior objects to associate two objects dynamically bound together for some reason.In the current API, it is possible to request the first parent of a given class via the parentOfClass() method. A general iterator that visits each parent would be useful, but is not yet available. Note that the parent list is maintained as an ArrayList of weak references; clients that access the array list directly should be prepared for null references to appear in the list.Remove behaviors from parentsBehaviors can be removed from their parent list in the same way that objects are usually removed from lists, via a direct call to the BehaviorList‘s remove method. In addition, behavior objects can be immediately removed from all lists they belong to by calling the behavior object’s removeFromAll() method. removeFromAll() iterates all of the parent lists and removes the behavior. This capability is extremely useful for implementing duration-based enchantments; when the timekeeper determines the enchantment has ended, it need only call removeFromAll() on the behavior object, and all of the objects that the behavior modifies will return to normal.Active sub-behaviorsA behavior can declare its sub-behaviors to be active—that is, to be seen by any object this behavior is added to—by implementing the ActiveSubBehaviors interface. Listing 5 shows an example of a behavior class that supports active sub-behaviors: Listing 5. Active sub-behaviors class DoublingBehavior extends Behavior implements FooInterface, ActiveSubBehaviors { ... BehaviorList fMySubBehaviorList; public Iterator inheritedSubBehaviors(Class behaviorClass, Object terminatingObject) { return fMySubBehaviorList.getInheritanceChain(behaviorClass, terminatingObject); } } When the behavior chain iterator sees that a behavior object implements ActiveSubBehaviors, it calls the inheritedSubBehaviors() method to request an iterator over the sub-behaviors to include. The implementation of inheritedSubBehaviors() should always appear exactly as shown in Listing 5.Other considerationsBehaviors introduce other considerations into an application’s design. Special care must be taken when cloning objects with behaviors, as adding behaviors to multiple parents creates a graph structure that cannot be cloned by the normal techniques. Also, the numerous classes a behavior-using application may acquire could add a lot of overhead to the work required to serialize the application’s objects.Thread safetyNote also that a behavior object can be attached to multiple dynamic objects. If this is done, in a multithreaded environment, take care when modifying the behavior’s state—it must be changed safely. Where possible, immutable behavior objects should be used; however, one of the advantages of POJO (plain-old-Java-object) behavior objects is that they can contain state relevant to the application functions they affect. If using behaviors in a multithreaded environment, plan ahead, considering ways that multithreaded access may affect your design.In addition to the behavior objects’ internal state, the behavior list itself is another object that might be affected in a multithreaded environment. Behavior objects have a convenient removeFromAll() method that removes them from all behavior chains they have been added to. In a typical behavior-based application, most likely, at some point, a behavior will be removed from its behavior lists while active iterators on those lists remain. Typical Java implementations of thread-safe lists use a “fails-fast” technique to invalidate all iterators when a list’s state changes.Behavior lists take a different approach and instead fix any iterator affected by a change to the list’s contents. Behaviors are by definition implemented as patches that can be applied and removed to executing programs. So usually, no ill effect should result from removing one behavior or another in the middle of a call chain.One example where it might cause a problem, though, would be if a single behavior modified two methods, and the implementation of the first patch took action it assumed would definitely be balanced by the call to the second patch. This assumption might be violated if the behavior was abruptly removed from between the two method calls. It is best to avoid such dependencies, but when that is not possible, a behavior object may override the notifyRemoved() method and test to see if any fix is needed. BehaviorList provides a method called hasIterator() that you can use to determine whether the current removal is affecting your iteration.Listing 6 demonstrates how a behavior object might detect the situation where it is removed unexpectedly. The assumption here is that methodTwo() is always called after methodOne(), and our example behavior takes advantage of that assumption to perform some cleanup.Listing 6. Detect behavior removal and apply fixup class ImprudentBehavior extends Behavior implements ExampleBehaviorInterface { Iterator fIteratorInProgress; public void methodOne(Iterator chain, int value) { // Do something imprudent and remember which behavior chain // we did it in fIteratorInProgress = chain; ((ExampleBehaviorInterface) chain.next() ).methodOne(chain, value); } public void methodTwo(Iterator chain) { this.fixupImprudentBehavior(); ((ExampleBehaviorInterface) chain.next() ).methodTwo(chain); } public void notifyRemoved(BehaviorList removedFromList) { if(removedFromList.hasIterator(fIteratorInProgress)) { this.fixupImprudentBehavior(); } super.notifyRemoved(removedFromList); } protected void fixupImprudentBehavior() { // Undo our stateful action fIteratorInProgress = null; } } You may find it ironic that the example given in the section on thread safety is not itself thread-safe (since fIteratorInProgress will be overwritten on recursive and/or multithreaded calls to methodOne). I deliberately wrote the example that way to keep it as short and clear as possible. I leave it up to you to extend the technique to handle multiple threads—a task that will hopefully encourage you to find an atomic way to solve the same problem without requiring a call to a fixup method.Note that I have never needed a behavior that sets and restores state as shown in Listing 6, so the code shown in that example is for reference only; it is completely untested.Clone a graph structureWhen behavior objects are attached to multiple objects in a tree-shaped hierarchy, the resulting structure is a graph. It is not possible to clone a graph using Java’s clonable mechanism; therefore, another technique is required. Even if using clonable were possible, it is not necessarily practical. Applications that use behaviors typically define numerous small classes, many of which contain just one method only a few lines long. The tedium of adding implements clonable and overriding the clone method could become burdensome and error-prone over time. A better approach is needed.Vladimir Roubtsov’s JavaWorld article “Attack of the Clones” (January 2003) compares different techniques for object cloning and presents their performance differences. The ReflectiveClone class he describes solves our problem nicely, duplicating an object graph and fixing internal references with acceptable performance. A derivative implementation is included in this article’s package (republished with permission), modified to fix weak references inside a subtree, but not follow them. The parent links maintained by behavior objects are stored via weak references. This allows a subtree of a complex object graph to be cloned without taking the entire universe of reachable objects with it.Note that the reflective clone algorithm cannot clone objects of classes that are instances of inner classes. (This restriction does not apply to static inner classes, only fully inner classes that contain implicit references to their parent objects.) Therefore, behaviors should not be implemented with inner classes.Serialize Dynamic BehaviorsSerializing graphs is possible, so object hierarchies that use behaviors can be serialized and transmitted using standard Java techniques. However, additional considerations to serialization might make it a bit too heavyweight for use in an application that extensively uses behaviors. Joshua Bloch’s book Effective Java (Addison-Wesley Professional, June 2001) covers this topic in items 54 through 57—important reading for anyone considering using serialization in a complex application containing many classes.One possible alternative to the serialization class is JAXB (Java Architecture for XML Binding), a component of the Java Web Services Developer Pack that serializes and deserializes object hierarchies to and from XML given an XML schema. However, JAXB handles only hierarchy trees, not graphs. I solved this problem by giving behaviors a primary parent that holds the behavior’s serialized form and keeps references to the other objects it modifies. After unmarshalling, I call a fixup method that reattaches the behaviors to its other parents.A full discussion of serialization techniques reaches beyond this article’s scope. Consider carefully the available options before moving too far into the system’s implementation, as changing serialization strategies can greatly affect an application’s design.Comparison to Aspect-Oriented ProgrammingAs already mentioned, the techniques described in this article are nothing new; they date back to MacApp 3.0, circa the early 1990s, and have roots in SmallTalk before that. The only new thing presented here is a specific implementation of the design pattern that makes it easy to quickly implement many distinct behavior objects with unique method signatures.Aspect-Oriented Programming (AOP) is a more recent invention receiving a lot of press lately. It is similar enough to Dynamic Behaviors that a comparison is useful.If you are unfamiliar with AOP, you might want to read the tutorial listed in Resources. The difficulty in comparing Dynamic Behaviors with AOP is that there are multiple implementations of the AOP paradigm, but no standard syntax or single set of features. In short, the two technologies are similar in that they both provide a mechanism for patching code at the beginning and end of class methods. The two technologies also have many differences.Most AOP implementations allow point-cuts (patches) to occur globally across all object instances of class methods, whereas dynamic behaviors are inserted on an instance-by-instance basis (that is, you must add a behavior object to every instance of a given class you wish to modify). However, one advantage that AOP offers is the ability to define a single aspect that point-cuts many methods. This approach is often done in an XML configuration file via a regular expression description of the method names that should be intercepted.Dynamic behaviors, on the other hand, modify individual instances of objects. To affect a change in behavior, you must attach a modifying object directly to the instance you wish to patch. If you consider enhancing this Dynamic Behaviors implementation so that it also provides global behaviors (for example, by adding static behavior lists, dispatching through singleton objects at the head of method calls, and so on), you might instead want to investigate AOP and leverage the available tools already supporting such functionality. For applications that fit into the usage model of Dynamic Behaviors, though, this design pattern is a simpler option that is easier to adopt and deploy.ConclusionThe Dynamic Behaviors pattern can provide better organization to programs that would otherwise need many if statements scattered throughout the code to implement conditional functions. However, like AOP, introducing Dynamic Behaviors into an application also complicates the control flow and makes it difficult to tell what code might execute before or after any given method of a particular class instance. Many problem domains are appropriate to the use of Dynamic Behaviors, but it is not a general-purpose programming technique. The judicious programmer must ensure that the benefits of a technology outweigh its costs before adopting it. Careful planning and diligent documentation practices are a must. If used correctly and carefully, the Dynamic Behaviors pattern provides a useful tool that will make your dynamic system design task easier to manage.Greg Anderson is an engineering manager at Ricoh corporation. He has been involved in software development since 1990; he has worked in groups building application frameworks (MacApp), system software (Macintosh Finder), international software (Macintosh Japanese Input Method) and network appliances (Ricoh eCabinet and Ricoh embedded Java). Design PatternsJavaSoftware Development