Matters of State

Post on 17-Jul-2015

176 views 0 download

Transcript of Matters of State

1 2 6 Java™Report | J U N E 2 0 0 0 ht t p : / / w w w. j ava re po rt . co m

ID E N T I T Y, STATE, AND behavior can typify anobject. For example, value objects1 , 2—used forre p resenting simple pieces of information in asystem, such as dates, strings, and quantities—

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 dto method calls quite diff e re n t l y, depending on whatgeneral state or mode their content re p resents. Objectsthat do not have significant identity tend to have less

i n t e resting life cycles. Astateless service object hasno state and there f o re nolife cycle; a value-basedobject tends to have eithera trivial life cycle model orno 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 .3 S t a t e c h a rt di-agrams can tell developers

a lot about the behavior of objects over time, and un-like many conventional class models, the move tocode is far from trivial. Java offers features that sim-plify the implementation of object life cycle models.

Ge n e ral Pat te rnO b je c ts for States is a general-purpose (as opposed tod o m a i n - s p e c i fic) pattern4 that can be used to movef 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 nameO b je c ts for States is used here in pre f e rence to itscommon 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 sb road intent, whereas O b je c ts for States d e s c r i b e ss t ru c t u re—and does not give the reader the impre s-

sion that this is the only solution style possible forobject life cycles; i.e., it is “a state pattern” not “t h estate pattern ” . *

St ate An ato my. Although often presented as a sin-gle pattern, many have re c o g n i z e d5 that there is ag 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 complexityor 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 ha pattern language.

P a t t e rn languages combine a number of pattern sinto a coherent whole, connecting them togethert h rough a set of decisions, with one pattern eff e c t i v e-ly completing another.1, 2 A pattern that plays a ro l ein a language does not belong exclusively to that lan-guage: It may be used to resolve similar problems inother pattern languages and contexts.

The Pat te rn s. A pattern language describes how tobuild a system or an aspect of a system. This art i c l elooks 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 howthe mode of the object is re p resented—as opposed to,s a y, how its transitions are managed. Figure 1 depictsthe basic flo w, showing that once O b je c ts for Stateshas been selected we have an either/or decision as tohow to best re p resent the objects housing the actualdelegated 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 thestatefulness (or otherwise) of a transactional middlet i e r. They are here woven into the language thro u g hcommon links and a shared example. The pattern sa 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.

Kevlin He n n ey is an indepe n d e nt co n s u l t a nt and trainer basedin the UK.

*Unfortunately, I have seen the havoc this misconception canwreak 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 ythey reduce rather than increase communication and under-standing. A clear name counts for a lot.

Kevlin He n n ey / kevlin@curbralan.comPatterns in Java

Matters of state

1 2 8 Java™Report | J U N E 2 0 0 0 ht t p : / / w w w. j ava re po rt . co m

Patterns in Java / Kevlin He n n ey

Objects forS t a t e sAllow an object toalter its behaviors i g n i f i c a n t l y b ydelegating state-based behavior toa separate object.

Pro b l e m . H o wcan an object sig-

n i ficantly change its behavior, depending on its intern a lstate, without h a rd w i red multipart conditional code? Thetemptation is to use a flag internal to the object and in eachmethod to switch to the correct behavior accord i n g l y. Thisc 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 tto locate the behavior for a particular mode, and harder stillto modify the behavioral model corre c t l y.

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 rstate. The context object—the instance of the main classwith which the client communicates—aggregates an ob-ject that is used to re p resent the behavior in one of itsmodes. Method calls on the context are forw a rded to themode object; responsibility for implementing behaviorin a particular state is there f o re delegated and localized.This behavioral mode object can be implemented as ei-

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 thebehavioral mode objects themselves or by a centralizedmechanism such as a table lookup.

To move with confidence from an existing design thatuses 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 hState/Strategy re f a c t o r i n g6 can 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 theircontext objects.

Ex a m p l e. Consider the life cycle for a simple clock shownin Figure 2.

Leaving aside the issue of transitions and time updates, a tempting procedural implementation can beseen in Listing 1. Such a contro l - flow-based approach ise rror prone and scatters the state-based behavior acro s smany methods.

Using O b je c ts for States t u rns the basic stru c t u re insideout 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).

Stateful ObjectAllow a behavioral object that is separate from the dataobject on which it operates access to that data by pro v i d i n ga field with a re f e rence back to it.

Pro b l e m . Given a separation of behavior from the statethat the behavior operates on, so that the state is one ob-ject and the behavior in another, what is the simplest andmost 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 behaviorcould 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 itoperates. Because of the knowledge of its context, it hasstate of its own. At any one time, a behavior object is ded-icated to a single context object.

Fi g u re 1. The Objects for States p a t te rn andthe co n s t ru ction of its re p re s e n t a t i o n .

Figure 2. Statechart representing the life cycle of a simple clock object.

L I S T I N G 1.

Implementation of the clock’s life cycle using a fla gand 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 = 1;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 ;

}

The simplest and most direct approach is to use innerclasses so that the context object’s state is implicitly visibleto 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 bed e fined, with either raw access to the data—through pack-age or class-level visibility—or via additional query andm o d i fier methods.

This retains the separation between behavior and the data of interest, but means that a behavioral object isnow tied to a single data object at a time. This can leadto increased object creation and collection costs, espe-cially if the behavior object is changed for another andthe previous object is discarded rather than cached. If this is significant, implementing the behavioral modeobject as a S t a t e less Obje c t re p resents an altern a t i v e .

Ex a m p l e. Implementing the clock class with a S t a t e f u lO b je c t for the mode leads to Listing 2. An improvement inthe creation/collection perf o rmance of the program wouldbe to preinstantiate all the re q u i red mode objects for an object and cache them in an arr a y.

Stateless ObjectAllow a behavioral object that is separate from the data ob -ject on which it operates access to that data by passing are f e rence back to it as an argument with each method call.

Pro b l e m . Given a separation of behavior from the state itoperates on, so that the state is in one object and the be-

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 toi n c reased object numbers and reduced perf o rmance if theobjects are created and discarded fre q u e n t l y.

So l u t i o n . Implement the behavioral class so that it hasno data in it whatsoever. The context object is nowpassed in as an argument to each of the delegated meth-ods of the behavioral objects. The simplest approach that

L I S T I N G 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 ( ) ;

}

Fi g u re 3. Re p resentation of the clock state model using O b j e c t sfor States.

1 2 9ht t p : / / w w w. j ava re po r t . co m J U N E 2 0 0 0 | Java™ Report

Kevlin He n n ey / Patterns in Java

L I S T I N G 3 .

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

}

allows behavioral objects to see the encapsulated contentof 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 methodsmust be pro v i d e d .

Such behavioral objects are stateless, so they may bet reated as F l y we i g ht4 objects that can be shared transpar-ently among all instances of the context class. The ab-sence of state also means that they are implicitlyt h readsafe, and there f o re need no synchronization. Giv-en that only a single instance of a behavioral class is everre q u i red, S i ng le to n4 can be used to good effect when thedefinition of the behavioral class is outside the contextclass. Otherwise, S i ng le to n is overkill where p r i vate staticdata 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 rnmay be used to put all the behavioral code back into thecontext 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 issometimes an option, it can make the implementation un-wieldy for large state models: The context class suff e r smethod 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 nA 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., themain pattern can be said to c o n t a i n or be completed by t h eother 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 opposedto 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 inthe realization of O b je c ts For States, but are not tied exclu-sively to it: The issues raised and resolutions given can befound in many object systems whether local or distributed,(e.g., EJB). ■

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 ExistingC o d e, Addison–We s l e y, 1999.

1 3 0 Java™Report | J U N E 2 0 0 0 h t t p : / / w w w. j ava re po r t . co m

Patterns in Java / Kevlin He n n ey