Pattern name: Structure-Shy Object Purpose: To make object descriptions independent of class names and robust to changes of class structure, augment the class graph to make it a grammar for parsing objects. Also known as: Object Parsing, Grammar, Syntax Tree Motivation: During evolution of an application class structures frequently change which implies updates to application objects. There is a strong need to use object representations which are robust under class structure changes. The creational patterns in [GOF] also recognize this need. The Structure-Shy Object pattern is a useful additional creational pattern. It is one of the most effective creational patterns. Applicability: The pattern is useful to object-oriented designs of any kind. It is especially useful for reading and printing objects in user-defined notations. An example of a poor design which can be improved by Structure-Shy Object is a design which contains many constructor calls to build composite objects. Structure-Shy Object is very helpful when you design a new language over which you have syntactic control and which you need to implement using classes. Structure: The pattern extends the application class structure so that each object knows about a parse and print function. An extension to the class structure definition defines the syntax of the objects. Example: Consider class definitions for fruit baskets: A Class named: Basket Which is a concrete class containing the following parts: A labeled part with label: contents which is of class Apple End of class definition. A Class named: Apple Which is a concrete class containing the following parts: A labeled part with label: v which is of class DemNumber End of class definition. We use the shorter class dictionary notation: Basket = <contents> Apple. Apple = <v> DemNumber. To describe a specific fruit basket, we would like to use the following description: object AppleBasket basket apple weight 35 end and to automatically produce the corresponding object: : Basket ( < contains > : Apple ( < v > : DemNumber "35" ) ) To achieve this, we decorate the class dictionary with syntax: Basket = "basket" <contents> Apple "end". Apple = "apple" "weight" <v> DemNumber. What is the benefit? The basket representations are very robust! Consider the following class dictionary: A Class named: Basket Which is a concrete class containing the following parts: The string: "basket" A labeled part with label: contains which is of class List With parameters: class Thing The string: "end" End of class definition. A Class named: Thing Which is an abstract class that is a: class Fruit or a class Basket Each of which has the following common parts: End of common parts. End of class definition. A Class named: Fruit Which is an abstract class that is a: class Apple or a class Orange Each of which has the following common parts: A labeled part with label: weight which is of class Weight End of common parts. End of class definition. A Class named: Apple Which is a concrete class containing the following parts: The string: "apple" End of class definition. A Class named: Orange Which is a concrete class containing the following parts: The string: "orange" End of class definition. A Class named: Weight Which is a concrete class containing the following parts: The string: "weight" A labeled part with label: v which is of class DemNumber End of class definition. A Class named: List Having the following parameters: S Which is a repetition class containing: Multiple occurances of the following: Instances of the class: class S End of class definition. In class dictionary notation: Basket = "basket" <contains> List(Thing) "end". Thing : Fruit | Basket. Fruit : Apple | Orange *common* <weight> Weight. Apple = "apple". Orange = "orange". Weight = "weight" <v> DemNumber. List(S) ~ {S} . The same basket description AppleBasket now defines the object: : Basket ( < contains > : Thing_List { : Apple ( < weight > : Weight ( < v > : DemNumber "35" ) ) } ) Consequences: Use of the Structure-Shy Object pattern leads to more robust and shorter object descriptions. It also results in easier testing of class structures before programming starts. The price we pay is that the syntax needs to be added carefully into the class dictionary to guarantee unique readability of the object descriptions. A variety of parsing conditions can be used like the LL(1) parsing conditions. Any class dictionary can be made to satisfy the LL(1) conditions by adding more syntax to it. Therefore, using the Structure-Shy Object pattern does not limit the object oriented design space. Using the Structure-Shy Object pattern has a positive effect on class design. It allows to test class structures for completeness in representing test objects. The class designer gets early feedback regarding structural completeness. The Structure-Shy Object pattern is very easy to use by someone who knows the concept of a grammar and how a grammar is used to parse sentences. It is even easier to use by language designers who design application specific little languages. Implementation: A variety of formalism are available to define grammars. Use the one you are familiar with and change it to make it also a class definition formalism defining both the classes and a grammar. We have used EBNF (Wirth) and modified it to make it simultaneously a class definition notation. There are two ways to implement the parsing: a parser generator like YACC can be used or a generic parser can be written. Various parsing strategies can be used, like LL, LR, LALR with LL(1) being the best in most cases. Use of a generic parser is recommended. It requires automatic generation of functions to access data members by index. Consider the Reflection pattern [Siemens] to implement the generic parser. Related Patterns: The Builder pattern and other creational patterns in [GOF] also attempt robust object definitions. The Interpreter pattern [GOF] uses a similar idea but fails to propose it for general object-oriented design. The Structure-Shy Object pattern is useful in conjunction with the Prototype pattern; it can be used to create the prototype in a structure-shy way. Known Uses: Demeter Tools, T-gen, applications of YACC, Beta and many more. K.Koskimies, H.Moessenboeck: Designing a Framework by Stepwise Generalization. Proc. of the European Software Engineering Conference ESEC'95, Sitges, Spain, Sept. 1995, Lecture Notes in Computer Science 989, pp. 479-497 ftp.ssw.uni-linz.ac.at/pub/Papers/Frameworks.ps.Z The concept of an object-oriented grammar corresponds to a class dictionary. References Chapters 11 and 16 in [DEM] describe the pattern in detail. For further references, check the bibliographic section of those chapters. GOF: @BOOK{gang-of-4, AUTHOR = "Erich Gamma and Richard Helm and Ralph Johnson and John Vlissides", TITLE = "Design Patterns: Elements of Reusable Object-Oriented Software", PUBLISHER = "Addison-Wesley", YEAR = "1995" } Siemens: @BOOK{buschmann:pattern-oriented, AUTHOR = "Frank Buschmann et al.", TITLE = "Pattern-oriented Software Architecture", PUBLISHER = "John Wiley and Sons", YEAR = "1997", SERIES = "", VOLUME = "", NOTE = "ISBN = 0-471-95869-7" } DEM: @BOOK{karl:demeter, AUTHOR = "Karl J. Lieberherr", TITLE = "Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns", PUBLISHER = "PWS Publishing Company, Boston", YEAR = "1996", NOTE = "ISBN 0-534-94602-X" } Exercise: Use your favorite grammar notation and modify it to also make it a class graph notation. ===================================================================