E N D
Patterns in Java Kevlin He n n ey/kevlin@ curbralan.com Matters of state I have state, simple behavior, and transparent identity. Objects with significant identity typically re p re s e n t the load-bearing stru c t u res in a system, such as per- sistent data and graphical objects. They are also typi- cally objects with significant life cycles that re s p o n d to method calls quite diff e re n t l y, depending on what general state or mode their content re p resents. Objects that do not have significant identity tend to have less D E N T I T Y, STATE, AND behavior can typify an object. For example, value objects1 , 2—used for re p resenting simple pieces of information in a system, such as dates, strings, and quantities— sion that this is the only solution style possible for object life cycles; i.e., it is “a state pattern” not “t h e state pattern ” . * St ate An ato my. Although often presented as a sin- gle pattern, many have re c o g n i z e d5that there is a g reat deal more to implementing such a collabora- tion than can be elegantly captured in a single pat- t e rn. A pattern that covers a great deal of complexity or describes a number of implementation altern a- tives can often be opened up to reveal a more in- volved decision stru c t u re better re p resented thro u g h a pattern language. P a t t e rn languages combine a number of pattern s into a coherent whole, connecting them together t h rough a set of decisions, with one pattern eff e c t i v e- ly completing another.1, 2A pattern that plays a ro l e in a language does not belong exclusively to that lan- guage: It may be used to resolve similar problems in other pattern languages and contexts. i n t e resting life cycles. A stateless service object has no state and there f o re no life cycle; a value-based object tends to have either a trivial life cycle model or no life cycle model (e.g., I m mu t a b le Va l u e1, 2) . The life cycle of an object can be modeled in UML using a Harel s t a t e c h a rt .3S t a t e c h a rt di- agrams can tell developers The Pat te rn s. A pattern language describes how to build a system or an aspect of a system. This art i c l e looks at the O b je c ts for States p a t t e rn from a Java perspective. It shows a fragment of a pro t o l a n g u a g e (i.e., a work in pro g ress), focusing specifically on how the mode of the object is re p resented—as opposed to, s a y, how its transitions are managed. Figure 1 depicts the basic flo w, showing that once O b je c ts for States has been selected we have an either/or decision as to how to best re p resent the objects housing the actual delegated behavior. Stateful Obje c t and S t a t e less Obje c t have applica- bility outside this context, e.g., in considering the statefulness (or otherwise) of a transactional middle t i e r. They are here woven into the language thro u g h common links and a shared example. The pattern s a re described using a simple i n t e n t - p ro b l e m - s o l u t i o n - e x a m p l e f o rm, with a simplified example. a lot about the behavior of objects over time, and un- like many conventional class models, the move to code is far from trivial. Java offers features that sim- plify the implementation of object life cycle models. Ge n e ral Pat te rn O b je c ts for States is a general-purpose (as opposed to d o m a i n - s p e c i fic) pattern4that can be used to move f rom a documented state model to a practical im- plementation. It demonstrates a classic use of del- egation into a class hierarc h y. Note that the name O b je c ts for States is used here in pre f e rence to its common name of S t a t e, as this is both a more accu- rate description of its stru c t u re —S t a t e d e s c r i b e s b road intent, whereas O b je c ts for States d e s c r i b e s s t ru c t u re—and does not give the reader the impre s- *Unfortunately, I have seen the havoc this misconception can wreak on a system: Every single statechart was converted un- questioningly into an implementation of “t h e State” pattern. Pat- t e rns solve particular problems well; if applied inappro p r i a t e l y they reduce rather than increase communication and under- standing. A clear name counts for a lot. Kevlin He n n ey is an indepe n d e nt co n s u l t a nt and trainer based in the UK. 1 2 6 Java ™Report | J UNE 2000 ht t p : / / w w w. j ava re po rt. co m
Patterns in Java/Kevlin He n n ey Objects for S t a t e s Allow an object to alter its behavior s i g n i f i c a n t l y b y delegating state- based behavior to a separate object. ther a Stateful Obje c t or a S t a t e less Obje c t. The transition to a diff e rent state means replacement of the behavior object by another of a diff e rent class. Poly- morphism replaces the explicit conditional lookup. Tr a n- sitions between states can be managed either by the behavioral mode objects themselves or by a centralized mechanism such as a table lookup. To move with confidence from an existing design that uses a type switch of some kind to one that takes advan- tage of O b je c ts for States, the Replace Type Code Wi t h State/Strategy re f a c t o r i n g6can be applied. The separa- tion and increased messaging through forw a rding meth- ods means that this design is not suitable for distribution; i.e., mode objects should live in the same process as their context objects. Fi g u re 1.The Objects for Statesp a t te rn and the co n s t ru ction of its re p re s e n t a t i o n . Pro b l e m . H o w can an object sig- n i ficantly change its behavior, depending on its intern a l state, without h a rd w i red multipart conditional code? The temptation is to use a flag internal to the object and in each method to switch to the correct behavior accord i n g l y. This c reates long and complex m e t h o d s . I t b e c o m e s d i ffic u l t to locate the behavior for a particular mode, and harder still to modify the behavioral model corre c t l y. Ex a m p l e. Consider the life cycle for a simple clock shown in Figure 2. Leaving aside the issue of transitions and time updates, a tempting procedural implementation can be seen in Listing 1. Such a contro l - flow-based approach is e rror prone and scatters the state-based behavior acro s s many methods. Using O b je c ts for States t u rns the basic stru c t u re inside out through delegation. All behavior relevant to a part i c u- lar mode is encapsulated in an object and the entire selec- tion is expressed through p o l y m o r p h i s m (see Figure 3). So l u t i o n . Separate the behavior from the main class, which holds the context, into a separate class hierarc h y, w h e re each class re p resents the behavior in a part i c u l a r state. The context object—the instance of the main class with which the client communicates—aggregates an ob- ject that is used to re p resent the behavior in one of its modes. Method calls on the context are forw a rded to the mode object; responsibility for implementing behavior in a particular state is there f o re delegated and localized. This behavioral mode object can be implemented as ei- Stateful Object Allow a behavioral object that is separate from the data object on which it operates access to that data by pro v i d i n g a field with a re f e rence back to it. LISTING 1. Implementation of the clock’s life cycle using a fla g and explicit switching. public class Clo c k { public sy nc h ronized void change Mo de() ... public sy nc h ronized void inc re me nt ( ) { s w i tc h ( mo de ) { case displaying T i me : t h row new Exc e p t i o n ( “ C h a nge mo de to change time ” ) ; b re a k ; case setting Ho u rs : + + ho u rs ; b re a k ; case setting M i nu t e s : + + m i nu t e s ; b re a k ; } } public sy nc h ronized void cancel() ... . . . p r i vate static final int displaying T i me = 0; p r i vate static final int setting Ho u rs p r i vate static final int setting M i nutes = 2; p r i vate int ho u rs, minu t e s ; p r i vate int mo de = setting Ho u rs ; } Pro b l e m . Given a separation of behavior from the state that the behavior operates on, so that the state is one ob- ject and the behavior in another, what is the simplest and most direct design for the behavioral class? The separa- tion means that whereas the behavior and data were pre- viously in the same object—and there f o re the behavior could act directly on it—the behavior can no longer di- rectly manipulate the data. So l u t i o n . Implement the behavioral class so that an in- stance has access to the contents of the object on which it operates. Because of the knowledge of its context, it has state of its own. At any one time, a behavior object is ded- icated to a single context object. = 1; Figure 2.Statechart representing the life cycle of a simple clock object. 1 2 8 Java ™Report | J UNE 2000 ht t p : / / w w w. j ava re po rt. co m
Kevlin He n n ey/Patterns in Java The simplest and most direct approach is to use inner classes so that the context object’s state is implicitly visible to the behavior classes. Altern a t i v e l y, an explicit back re f- e rence from the behavior object to the context object can be d e fined, with either raw access to the data—through pack- age or class-level visibility—or via additional query and m o d i fier methods. This retains the separation between behavior and the data of interest, but means that a behavioral object is now tied to a single data object at a time. This can lead to increased object creation and collection costs, espe- cially if the behavior object is changed for another and the previous object is discarded rather than cached. If this is significant, implementing the behavioral mode object as a S t a t e less Obje c t re p resents an altern a t i v e . Fi g u re 3.Re p resentation of the clock state model using O b j e c t s for States. havior in another, what design for the behavioral class min- imizes object creation and collection costs? A Stateful Ob- je c t is simple to implement and manage, but can lead to i n c reased object numbers and reduced perf o rmance if the objects are created and discarded fre q u e n t l y. Ex a m p l e. Implementing the clock class with a S t a t e f u l O b je c t for the mode leads to Listing 2. An improvement in the creation/collection perf o rmance of the program would be to preinstantiate all the re q u i red mode objects for an object and cache them in an arr a y. So l u t i o n . Implement the behavioral class so that it has no data in it whatsoever. The context object is now passed in as an argument to each of the delegated meth- ods of the behavioral objects. The simplest approach that Stateless Object Allow a behavioral object that is separate from the data ob - ject on which it operates access to that data by passing a re f e rence back to it as an argument with each method call. LISTING 3. Pro b l e m . Given a separation of behavior from the state it operates on, so that the state is in one object and the be- Implementation of the clock’s life cycle using a Stateless Object for the mode. public class Clo c k { public sy nc h ronized void change Mo de ( ) { mo de. c h a nge Mo de(this); } public sy nc h ronized void inc re me nt ( ) { mo de. i nc re me nt(this); } public sy nc h ronized void canc e l ( ) { mo de. c a ncel(this); } p r i vate int e r face Mo de { void change Mo de ( C lock cont ex t ) ; void inc re me nt ( C lock cont ex t ) ; void canc e l ( C lock cont ex t ) ; } p r i vate static class Displaying T i me imple me nts Mo de ... p r i vate static abstract class Setting T i me imple me nts Mo de . . . p r i vate static class Setting Ho u rs ex t e nds Setting T i me ... p r i vate static class Setting M i nutes ex t e nds Setting T i me { public void change Mo de ( C lock cont ex t ) { cont ex t . mo de = displaying T i me; } public void inc re me nt ( C lock cont ex t ) { ++cont ex t . m i nutes; } } p r i vate int ho u rs, minu t e s ; p r i vate Mo de mo de = setting Ho u rs ; p r i vate static final Mo de d i s p l a y i ng T i me = new Displaying T i me ( ) , s e t t i ng Ho u rs = new Setting Ho u rs ( ) , s e t t i ng M i nutes = new Setting M i nu t e s ( ) ; } LISTING 2. Implementation of the clock’s life cycle using a Stateful Object for the mode. public class Clo c k { public sy nc h ronized void change Mo de() { mo de. c h a nge Mo de(); } public sy nc h ronized void inc re me nt() { mo de. i nc re me nt(); } public sy nc h ronized void cancel() { mo de. c a ncel(); } p r i vate int e r face Mo de { void change Mo de ( ) ; void inc re me nt ( ) ; void canc e l ( ) ; } p r i vate class Displaying T i me imple me nts Mo de ... p r i vate abstract class Setting T i me imple me nts Mo de { public void cancel() { mo de = new Displaying T i me(); } } p r i vate class Setting Ho u rs ex t e nds Setting T i me ... p r i vate class Setting M i nutes ex t e nds Setting T i me { public void change Mo de() { mo de = new Displaying T i me(); } public void inc re me nt() { ++minutes; } } p r i vate int ho u rs, minu t e s ; p r i vate Mo de mo de = new Setting Ho u rs ( ) ; } 1 2 9 J UNE 2000 |Java ™Report ht t p : / / w w w. j ava re po rt. co m
Patterns in Java/Kevlin He n n ey allows behavioral objects to see the encapsulated content of the context objects is to declare them as s t a t i c t o p - l e v- el classes in the context class. Altern a t i v e l y, package-lev- el visibility or additional query and modifier methods must be pro v i d e d . Such behavioral objects are stateless, so they may be t reated as F l y we i g ht4objects that can be shared transpar- ently among all instances of the context class. The ab- sence of state also means that they are implicitly t h readsafe, and there f o re need no synchronization. Giv- en that only a single instance of a behavioral class is ever re q u i red, S i ng le to n4can be used to good effect when the definition of the behavioral class is outside the context class. Otherwise, S i ng le to n is overkill where p r i vate static data would suffic e . The entire selection of behavior is now expressed pure- ly through polymorphism and callbacks on a separate ob- ject, and the state now resides only in the context object. If the behavioral model is quite stable, the V i s i to r p a t t e rn may be used to put all the behavioral code back into the context object, with the behavioral mode object doing se- lection only and calling the relevant method on the con- text object to do all of the work. However, although this is sometimes an option, it can make the implementation un- wieldy for large state models: The context class suff e r s method explosion. Ex a m p l e.Implementing the clock class with a S t a t e less Ob- je c t for the mode leads to Listing 3. Co n c l u s i o n A common pattern for implementing object life cycle mod- els can be expressed in terms of other more granular pat- t e rns. They may be linked together in a language; i.e., the main pattern can be said to c o n t a i n or be completed by t h e other patterns. In this article, the focus was on the re p re- sentation of the O b je c ts for States p a t t e rn in Java, as opposed to a more detailed view of the whole pattern .5 The Stateful Obje c t and S t a t e less Obje c t p a t t e rns assist in the realization of O b je c ts For States, but are not tied exclu- sively to it: The issues raised and resolutions given can be found in many object systems whether local or distributed, (e.g., EJB). I Re fe re n ce s 1 . H e n n e y, K., “Patterns of value,” Java Report , Vol. 5, No. 2, Feb. 2000, pp. 64–68. 2 .H e n n e y, K., “Value added,” Java Report , Vol. 5, No. 4, Apr. 2000, pp. 74–82. 3 . Rumbaugh, J., I. Jacobson, and G. Booch, The Unified Mod - eling Language Reference Manual, Addison–We s l e y, 1999. 4 . Gamma, E. et al., Design Patterns: Elements of Reusable Ob - ject-Oriented Software, Addison–We s l e y, 1995. 5 . Dyson, P. and Anderson, B. “State Patterns,” P a t t e rn Lan - guages of Program Design 3, R. Martin, D. Riehle, and F. Buschmann, Eds., Addison–We s l e y, 1998. 6 .F o w l e r, M., Refactoring: Improving the Design of Existing C o d e, Addison–We s l e y, 1999. 1 3 0 Java ™Report | J UNE 2000 ht t p : / / w w w. j ava re po rt. co m