1 / 5

Collections for States

Collections for States (Java Report 5(8), August 2000).

Kevlin
Télécharger la présentation

Collections for States

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Patterns in Java Kevlin He n n ey/kevlin@ curbralan.com Collections for States I on capturing recurring practice—but at other times force of habit is the real decision maker. Patterns are all about capturing breadth as well as depth of knowledge, and we can find that problems that seemed similar have enough minor differences that the appropriate solutions are in fact poles apart. Consider implementing a life cycle model for an object. It is tempting to use a fla g - a n d -s w i tc h a p p ro a c h , N DESIGN, AS with anything in life, we often fall into a groove, repeating the same solutions time and again. Sometimes this is appropriate— hence the emphasis in the patterns community agement divided between the collected objects and their managers? Ex a m p l e Consider an application that holds a number of graphical objects that may be manipulated by a user, such as a CAD tool or graphical editor. The general shape of this application follows from the Workpieces frame.4The objects manipulated by the user are the workpieces, and these may be saved to some kind of persistent storage, for example, a data- base. These objects all share a simple life cycle model (see Figure 1) in addition to their type-spe- cific state. For such a simple state model, the use of the Objects for States pattern1,2—where a class hierarchy is introduced to reflect the separate states and the behavior associated with them—would be overkill. Instead, we can use a simpler flag-based approach, representing state as an attribute. In Java this would lead to the code in Listing 1. The saveState method acts as a Template Method.1 In an application, which acts as the manager for workpiece objects, saving all the changes since the last save could be implemented as shown in Listing 2.*H o w e v e r, this suffers from a verbose control stru c t u re and an excessive amount of checking. We might try to simplify the application class logic with the re a rrangement of responsibilities shown in Listing 3. Here we have hidden the condition check to simplify usage. H o w e v e r, both of these approaches fail to addre s s the basic flaw: the brute force of the “linear s e a rch, query, then act” model. This is both cum- bersome and inefficient, especially where many but this is often clumsy for models with significant b e h a v i o r. O b je c ts for States (commonly known as the S t a t e p a t t e rn )1 , 2a l l o w s s t a t e - s p e c i fic b e h a v i o r t o b e re p re s e n t e d e l e g a n t l y t h ro u g h a delegation and i n h e r i t a n c e s t ru c t u re . H o we v e r, it is not the case that O b je c ts for States is t h e s t a t e p a t t e rn , a n d t h a t other techniques—includ- ing fla g s — a re inappropriate in realizing state models. The C o l le c t i o ns for State p a t t e rn addresses the imp- lementation of simple state models over collections of objects. Pro b l e m Consider a collection of similar objects managed by another object. The managed objects have life cycles with only a few distinct states, and the Manager object3often operates on them collectively with respect to the state they are in. These objects can be modeled as individual state machines. What is a suitable model for the collected objects and their managing objects that empha- sizes and supports this independence? How is the responsibility for state re p resentation and man- Figure 1.Statechart representing the simple life cycle of a workpiece object. * Note that for bre v i t y, and to keep a focus on the core pro b- lem at hand, handling of threading and exception issues are omitted from the code. 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. 9 2 Java ™Report | AUGUST 2000 ht t p : / / w w w. j ava re po rt. co m

  2. Patterns in Java/Kevlin He n n ey LISTING 3. The workpiece assumes responsibility for saving or not, depending on its state. public abstract class Wo r k p i e c e { public void save ( ) { i f ( c h a nge d ) { s a ve S t a t e ( ) ; c h a nged = fa ls e ; } } . . . } LISTING 1. R e p resentation of workpiece saved as a fla g . public abstract class Wo r k p i e c e { public void save ( ) { s a ve S t a t e ( ) ; c h a nged = fa ls e ; } public boolean save d ( ) { return !change d ; } . . . p rotected abstract void save S t a t e ( ) ; p r i vate boolean change d ; } public class Application { public void save C h a nge s ( ) { It e ra tor workpiece = change d . i t e ra to r ( ) ; w h i le ( wo r k p i e c e. h a s N ex t ( ) ) ( ( Workpiece) wo r k p i e c e. nex t ( ) ) . s a ve ( ) ; } . . . } workpiece objects exist but only a small pro p o rtion are modified between saves. Fo rce s For an object whose own behavior changes substantially depending on its state in a life cycle, the most dire c t implementation is for the object to be fully aware of its own state, meaning the object is self-contained and includes all of the mechanisms for its behavior. This a w a reness strengthens the coupling between the object and its life cycle, and increases the footprint of the indi- vidual object. For simple state models, flag-based solutions are attractive because they do not re q u i re much code stru c- turing eff o rt, although they may lead to simplistic code with a lot of repetition and explicit, hard - w i red contro l flo w. With O b je c ts fo r S t a t e s, selection is expre s s e d t h rough polymorphism and behavior within a state is modeled and implemented cohesively. This allows g reater independence between the object and its state model, but can be complex in implementation, and, for l a rge state models, it is very easy to lose sight of the life cycle model. State transition tables can be used to drive and increase the flexibility of either the flag-based or the O b je c ts for States a p p roach, or they may be used indepen- d e n t l y. In all of these cases the object is tied to a single given life cycle model. If the object’s own behavior is l a rgely independent of its state, and such state behavior is l a rgely governed by its application context, an intern a l re p resentation of the life cycle can increase the coupling of the object to its enviro n m e n t . If an object’s life cycle is managed extern a l l y, the object is independent of its context and its re p re s e n t a- tion is simplified. However, this means that signific a n t decisions about the object’s behavior are now taken out- side the object. One of the benefits of flag variables, O b je c ts for States, or state transition tables is that the state model is made explicit intern a l l y. Objects are fully a w a re of what state they are in and can act appro p r i a t e- l y w h e n u s e d o u t s i d e t h e c o l l e c t i v e . A l s o , a n y o n e e x a m i n i n g t h e c l a s s c a n e a s i l y d e t e rm i n e its objects’ possible life cycles. Modeling states explicitly and internally means that changes to the life cycle model re q u i re changes to the class code. So life cycles cannot easily be modified inde- pendently of the class’s re p re s e n t a t i o n . With O b je c ts for States, having additional state-depen- dent data is relatively simple: The class re p resenting a p a rticular state also defines any data that is relevant to objects in that state. For flag-based or state transition tables the data must be held elsewhere, typically as potentially redundant data within the stateful object. If LISTING 2. Saving all changed workpiece objects by querying then saving them. public class Application { public void save C h a nge s ( ) { It e ra tor workpiece = change d . i t e ra to r ( ) ; w h i le ( wo r k p i e c e. h a s N ex t ( ) ) { Workpiece curre nt = (Workpiece) wo r k p i e c e. nex t ( ) ; i f ( ! c u r re nt . s a ve d ( ) ) c u r re nt . s a ve ( ) ; } } . . . p r i vate Collection wo r k p i e c e s ; } 9 4 Java ™Report | AUGUST 2000 ht t p : / / w w w. j ava re po rt. co m

  3. Patterns in Java/Kevlin He n n ey the life cycle is managed extern a l l y, extra state-depen- dent data can introduce the same management burd e n ; i.e., the manager must add additional context data to its collection entry, or potentially redundant data must be held within the object. With collections of objects in which objects in the same state receive uniform treatment, an internal state re p resentation can lead to poor perf o rmance. All col- lected objects are traversed re g a rdless of the state they a re in, and a state-based decision is taken for each one: e x p l i c i t l y, in the case of flag variables; implicitly t h rough polymorphic lookup, in the case of O b je c ts fo r S t a t e s; implicitly through table lookup, in the case of state transition tables. In each case, eff o rt is wasted tra- versing all objects only to perf o rm actions on a subset. E x t e rnal life cycle management can support a concep- tually more direct approach, which also has perf o r- mance benefit s . LISTING 5. Adding a single collection to hold all of the objects m a n a g e d . public class Application { . . . C o l lection wo r k p i e c e s, saved, change d ; . . . } object simply needs to run through the c h a nge d c o l l e c- tion saving each workpiece there, and then merge them back into the s a ve d c o l l e c t i o n . If we need to treat all of the objects collectively, re g a rd- less of state, it would be tedious to set up two loops to ru n t h rough all of the objects—one for s a ve d and one for c h a nge d—and so we can re p resent the superstate of saved and changed workpiece objects—i.e., all workpiece objects, with an additional collection (see Listing 5). The extra collection is the “boss” collection, holding all of the objects in a definitive order. It is used for state- independent operations that apply to all the objects. The constraint is clearly that objects can only be present in one of the two state collections but must be present in the boss collection, and any object present in the boss collection must be present in one of the state collections. In the context of this application, if unsaved objects are of interest because we can collectively save them, but saved objects are not operated on as a group, we can refactor to eliminate the use of the s a ve d collection (see Listing 6). So l u t i o n Represent each state of interest by a separate collection that refers to all objects in that state. The manager object holds these state collections and is responsible for man- aging the life cycle of the objects. When an object changes state, the manager ensures that it is moved from the collection representing the source state to the collec- tion representing the target state. Re s o l u t i o n Applying this solution to our example leads to the code s t ru c t u re shown in Listing 4. This is both signific a n t l y simpler and more efficient, in terms of traversal, than the previous attempts. The s a ve d collection refers to the objects that are unchanged, and when modified via the application these are transferred to the c h a nge d c o l l e c- tion. As this is a re f e rence move, it is cheap. To save all of the changed workpiece objects, the application Co n s e q u e n ce s By assigning collections to represent states we can now move all objects in a particular state into the relevant col- lection and perform actions on them together. Other than selecting the correct collection for the state, there is no selection or traversal required. Thus, this is both a clean- er expression of the model and a more time efficient one. An object’s collection implicitly determines its state, so there is no need to also represent the state internally. Because the objects are already being held collectively, this can lead to a smaller footprint per object, which can be considered a benefit for resource constrained environ- LISTING 4. Applying the proposed solution to the exa m p l e. public abstract class Wo r k p i e c e { public abstract void save ( ) ; . . . } LISTING 6. Ignoring a collection for saved objects. public class Application { public void save C h a nge s ( ) { It e ra tor workpiece = change d . i t e ra to r ( ) ; w h i le ( wo r k p i e c e. h a s N ex t ( ) ) ( ( Workpiece) wo r k p i e c e. nex t ( ) ) . s a ve ( ) ; c h a nge d . c le a r ( ) ; } . . . p r i vate Collection wo r k p i e c e s, change d ; } public class Application { public void save C h a nge s ( ) { It e ra tor workpiece = change d . i t e ra to r ( ) ; w h i le ( wo r k p i e c e. h a s N ex t ( ) ) ( ( Workpiece) wo r k p i e c e. nex t ( ) ) . s a ve ( ) ; s a ve d . add A l l ( c h a nge d ) ; c h a nge d . c le a r ( ) ; } . . . p r i vate Collection saved, change d ; } 9 6 Java ™Report | AUGUST 2000 ht t p : / / w w w. j ava re po rt. co m

  4. Kevlin He n n ey/Patterns in Java ments but need not be a necessary consequence of apply- ing this pattern. Adding back-references from the object to its collection or manager would lose this space saving. The manager object now has more responsibility and behavior, and the managed object less. On the one hand, this can lead to a more complex manager; on the other, it means that the object life cycle model can be changed independently of the class of the objects. The state model can be represented within the manager using Objects for States, state transition tables, or explicit hardwired con- ditional code, as in the motivating Example section. The state management can become more complex if, in changing, the state model acquires significantly more states and therefore more collections to manage. Multiple state models can be used without affecting the class of the objects. For instance, we can introduce orthogonal state models for the objects in the motivating example based on their Z-ordering, versioning, or some other property, e.g., if they are active objects whether or not they are currently active. When orthogonal life cycles are involved, allocating separate managers for different state models simplifies the implementation: A single manager would become significantly more complex through acquisition of this extra responsibility. Where the manager acts as some kind of Broker,5all communication with the objects will be routed through it and therefore the manager will be fully aware of what changes objects might undergo. If objects can be acted on independently, state-changing events must not cause the manager to keep the wrong view, and so the manager would have to be notified. The notification collaboration can be implemented as a variation of the Observer pat- tern,1with the object either notifying the manager of a change or requesting a specific state transition of the manager. This would result in the object maintaining a back pointer to the manager, which would increase the complexity of the code, create a dependency on the man- ager, and increase the object’s footprint. A bidirectional relationship can also arise if the object’s own behavior is not completely independent of the man- a g e r’s view of it, and must there f o re have some aware n e s s of its own state. In this case, an alternative is to adopt some redundant internal state that acts as a cache. There are as many collections as there are states of interest in the life cycle. Figure 2 includes superstates or a boss collection that holds all of the objects (notionally a superstate of all of the states for the objects, anyway). Thus, this pattern can be applied recursively, and each superstate collection corresponds to the union of the cor- responding substate collections. A boss collection is nec- essary where all of the objects need to be treated collec- tively, as in a display or update. Iterating through many separate collections is not appropriate either because of convenience or because of ordering. The presence of a boss collection may obviate the need for one of the state collections; i.e., there are no collective operations per- formed in that state and the object is already accounted Fi g u re 2.Schematic re p resenting the fe a t u res of the p ro posed solution. for in the boss collection. It is not as easy to accommodate additional state- dependent data for each object as to manage the state externally. Either the object must hold redundant state or it must be held along with the object’s entry in the collection state. This leads to an increase in code com- plexity and runtime footprint. For instance, in the motivating example we could hold additional data for saved objects, indicating when they were last saved, or for changed objects to record when they were changed. W h e re the frequency of state change is high this pattern can become impractical: The mediation of state change f rom one collection to another via a manager can come to dominate the execution time of the system. Internal re p re- sentations have the benefit of immediacy when objects are acted on individually and with frequent state changes. The Collections for States pattern can be used in con- junction with other life cycle implementations as an optimization. For instance, in a library where each loan knows its due date, an explicit collection of overdue loans can be cached for quick access, rather than requir- ing a search over all loans for each inquiry. Di s c u s s i o n In C o l le c t i o ns for States, variation in state is expre s s e d t h rough collection objects rather than through polymor- phic classes. In this, and many other respects, it is inside out when compared to O b je c ts for States, with state modeled extrinsically rather than intrinsically, i.e., the life cycle is w o rn on the outside. It is focused on collections of objects rather than individual objects, and the entity/b e h a v i o r separation is in the opposite direction, with behavior man- aged by the collective rather than something within the individual. Such structural inversion illustrates that solu- tions to apparently similar problems, such as state man- agement need not be similar: Radically diff e rent stru c t u re s , w h e re roles and responsibilities are almost re v e r s e d between the solution elements, can arise from part i c u l a r d i ff e rences in the context and problem statement. A set of decisions can guide developers to weigh up the use of this pattern, as opposed to or in conjunction with Objects for States, state transition tables, and flag- based approaches, suggesting that all these approaches can be related within a generative framework, i.e., a pat- tern language. Such a language could be integrated with and extend existing state implementation languages.2,6 Where independence and collective requirements domi- 9 7 AUGUST 2000 |Java ™Report ht t p : / / w w w. j ava re po rt. co m

  5. Patterns in Java/Kevlin He n n ey nate, Collections for States proves to be a good match, lead- ing to a better representation of the conceptual model and a simplification of object implementation. We can see this pattern in systems programming and operating systems. It is the strategy used in file systems for handling free as opposed to used file blocks. It is used by many heap managers for holding free lists, especially debugging heap managers that track memory usage, i.e., f ree, used, and freed. Schedulers hold separate queues to schedule processes, which may be in various diff e re n t states of readiness—e.g., running, ready to run, or blocked. The theme of processing states can also be seen at a higher level in GUI systems supporting a comprehensive edit com- mand history facility. Once initially executed, a command can be in one of two states, either done so that it can be undone or undone so it can be redone. In this case, the col- lections used are quite specific and must support stack- o rd e red (last-in/first-out) access. An example of this can be seen in the C o m m a nd Pro c e s s o r p a t t e rn .5 Collections for States is also a common strategy for denormalizing a relational database. The library loan example would include a table representing overdue loans. The low frequency of state change and the relative sizes of the collections make this external state model an efficient and easy to manage caching strategy, optimizing lookup for queries concerning overdue books. We also see a similar structure in action in the real w o r l d w h e n p e o p l e a re g ro u p e d t o g e t h e r b e c a u s e o f some aspect of state, for example, queuing at airports with respect to EU and non-EU passports. I Ac kn ow l e d g m e nt s T h i s a rt i c l e i s b a s e d o n a p a p e r w o r k s h o p p e d a t t h e E u ro P L o P ’ 9 9 c o n f e re n c e . I w o u l d l i k e t o t h a n k P a u l Dyson, Charles Weir, Brad Appleton, Frank Buschmann, a n d t h e re s t o f t h e P O S A t e a m a t S i e m e n s , a n d the members of the EuroPLoP ’99 Writers’ Workshop who reviewed the original paper. Re fe re n ce s 1.Gamma, E. et al., Design Patterns: Elements of Reusable Object-Oriented Software, Addison–Wesley, 1995. 2.Henney, K., “Matters of State,” Java Report, Vol. 5, No. 6, June 2000, pp. 126–130. 3.Sommerlad, P., “Manager,” Pattern Languages of Program Design 3, R. Martin, D. Riehle, and F. Buschmann, Eds., Addison–Wesley, 1998. 4.Jackson, M., Software Requirements & Specifications: A Lexicon of Practice, Principles and Prejudices, Addison–Wesley, 1995. 5.Buschmann, F. et al., Pattern-Oriented Software Architecture: A System of Patterns, John Wiley & Sons, 1996. 6.Dyson, P. and B. Anderson, “State Patterns,” Pattern Languages of Program Design 3, R. Martin, D. Riehle, and F. Buschmann, Eds., Addison–Wesley, 1998. Real W o rld Java continued from page 30 S co t t’s So l u t i o n scontinued from page 104 “None of the problems we’re having with Java are showstoppers,” says Brilon. “They are all problems we can work around. And, at the end of the day, when we can tally up the math of what we’re doing, we see the advantages far outweigh the disadvantages. So we’re happy with our decision.” I HTML has two types of tags: those which come in pairs (< b o d y > and < / b o d y >) and those that do not (< p >). This sec- ond type of tag must be handled in the h a nd le S i m p le Tag ( ) method. In our case, we don’t care about those tags; we simply print them out if the d u m p O K flag is set to tru e . T h a t ’s basically all there is to it, although to complete the example, we’d really need to do a lot more work. We’d have to keep track of anchors in each document to make sure they are not repeated, and we’d want to change hyperlinks between the original documents to hyperlinks within our new single document. We might want to insert <hr> tags every time a document ends to indicate a visual separation between chapters; we could do that by printing < h r > in the h a nd le E nd Tag ( ) m e t h o d when the tag in question is H T M L . Tag . H T M L. However, you might want to manipulate the HTML, the document parser gives you an easy way to do it. I U R Ls Apache So ftwa re Fo u n d at i o n w w w. a p a c h e. o rg En hyd ra . o rg w w w. e n hyd ra . o rg MySQL dow n l o a d we b. mys q l . co m Li n u x w w w. l i n u x . o rg Bl a c k d ow n w w w. b l a c k d ow n . o rg Inte l w w w. i nte l . co m Lu t ris In c. w w w. l u t ri s. co m Sun Mi c ro s ys tems In c. w w w. s u n . co m Penguin Sys tems In c. w w w. pe n g u i n co m p u t- i n g. co m Palm In c. w w w. p a l m . co m Write to Us Send co m m e nt s,suggestions for to p i c s,e tc.to Managing Ed i tor Anna M.Kanson at a ka n s o n @ s i g s. co m Mi c ro s o ft Co rp. w w w. m i c ro s o ft. co m Red Hat Sys tems In c. w w w. re d h at. co m Philip J. Gill is As s oc i ate Ed i tor of Java Re po rt.He can be co nt a cte d at java b u z z @ s i g s. co m . 9 8 Java ™Report | AUGUST 2000 ht t p : / / w w w. j ava re po rt. co m

More Related