This book is an introduction to a new class of design pattern, the Elemental Design Patterns, which form a foundation for the study and application of software. of Hazrat Mawlana Jalaluddin Rumi's work, regardless of who they are and Immersing oneself in the ocean of love and co. PDF | The decomposition of design patterns into simpler elements may reduce significantly the creation of variants in forward engineering, while it increases the .
|Language:||English, Spanish, German|
|Distribution:||Free* [*Sign up for free]|
Elemental Design Patterns [Jason McC. Smith] on rieverkoratou.ml *FREE* shipping on qualifying offers. After fifteen years, the field of design patterns is still . Visit us on the Web: rieverkoratou.ml Library of Congress Cataloging-in- Publication Data. Smith, Jason McC. (Jason McColm). Elemental design patterns / Jason. Elemental Design Patterns: A Formal Semantics for Composition of OO. Software Architecture. Jason McC. Smith, David Stotts. University of North Carolina at.
But carnivores had lower P than their prey and shredders had higher N than filter feeders, gatherers and scrapers. Future work should attempt to assess the role of energy limitation and other potential drivers of the differing results for C, N and P distribution across trophic levels. Finally, the authors observed large variation in P, N:P ratio and C:P ratio within species across geographic space and geography impacted the magnitude but not the qualitative relationships observed.
A number of features make this study a strong test of the potential sources of variation in consumer elemental variation. First, the study design with multiple sites spanning a large latitudinal gradient offers a unique macroecological perspective which could shed light on general drivers and context dependencies in elemental composition with implications for ecosystem processes. This study is part of the growing field of spatial ecological stoichiometry Collins et al.
Second, the attention to testing multiple competing and interacting factors i. While Gonzalez et al. Two ways to overcome the immense challenge of collecting food web data across large spatial extents are to study relatively simple ecosystems e.
NutNet, Borer et al. Ecological stoichiometry has a long history in aquatic ecosystems, but we know that energy and nutrient flows differ substantially in aquatic and terrestrial ecosystems Elser et al.
Mathematical models integrating food web and ecosystem theories Loreau, can contribute to advancing this research agenda. Marleau and C. By the end of it, you should have a new set of tools in your toolbelt, a richer understanding of some of the basic concepts of programming that we all use every day, and knowledge of how they relate and interact with one another to do amazing things. This body of work gives them explicit descriptions, regularized names to use in discussions, and a framework for using them in concert and for comparing them on their own merits.
This book assumes you have a passing familiarity with design patterns as a field but have not used or studied them in detail. Knowing that they exist and having a brief colloquial knowledge of what they are is enough to start the discussion. The book does not assume you have a background in programming theory, language design, or even a strong one in object-oriented programming, just a desire to learn how to think critically about software design.
These subjects will be touched on but only as a starting point for those interested in diving deeper into them through xxi From the Library of Santiago Itzcoatl Salinas Reyna xxii Preface the provided references. The Unified Modeling Language is used to describe small examples, and I suggest either  or  as references if you do not already know UML.
You should have a basic foundation in programming, either procedural or object oriented. Developers experienced with object-oriented systems may still be surprised at finding new perspectives on concepts that they thought they had mastered long ago and a greater appreciation for object-oriented programming as a whole.
By giving you a new perspective on what can constitute a design pattern, this book should convince you that every programmer is a member of the design patterns community, whether they know it or not.
Nor are they likely to realize the options they have at their disposal. Design patterns are the shared conceptual space in which we write the electronic dreams that shape our world. Following the example of the seminal Gang of Four text , this book is divided into two sections. This section explains the rationale, the why, behind the EDPs. Next is an introduction to the Pattern Instance Notation, a diagramming system for working with patterns at many levels of granularity and in a multitude of environments.
Wrapping up this first section is a discussion of how EDPs can be used to build up to, and in conjunction with, the greater design patterns literature. The second section of the book is a collection of design patterns, starting with the EDPs and working through examples of how they combine to form Intermediate patterns, and finally, a selection of the Gang of Four patterns recast as EDP compositions. The EDPs presented here are only a portion of the EDP Catalog, a collection of the first round of defined and described fundamental patterns.
The software engineering community will continue to define and refine additional EDPs as the underlying concepts take root.
I hope you decide to help in the endeavor. In not quite chronological order. You each added invaluable help at critical times. From my years at IBM Watson Research in New York, Sid Chatterjee again, who convinced me to come play in the Big Blue Playpen; Clay Williams, who gave me free rein to pursue these crazy ideas further and with whom I still miss having coffee; Peter Santhanam, who championed those ideas and from whom I learned a greater appreciation for legacy systems; Brent Hailpern, from whom I learned many valuable lessons in management, the dark humor of corporate life and simple humanity; Edith Schonberg, who put up with my shenanigans more than any manager should have to; and many others who listened to me maniacally talk about this body of work at every turn.
My friends, I miss you all. Grady, your guidance, mentoring, and advocacy have been immeasurable, and I look forward to future collaborations and continued friendship.
From The Software Revolution, Inc. It has been a true pleasure working with all of you, and I am eager to see where we can take our company. To my many reviewers, your advice and comments were highly insightful and helpful. You made this book a much better product, and you have my deepest thanks: Elizabeth Ryan, Raina Chrobak, Chris Zahn, and Chris Guzikowski at Addison-Wesley were the model of compassionate support during the trials of this process—my thanks to you and the rest of the crew there, with a special thanks to Carol Lallier, whose expert polish on this book was invaluable.
Finally, my wife Leah. You have supported me in so many large and small ways throughout our time together. You have given your time, your patience, and your love, and you have my immense love and gratitude. Thank you.
Words are simply inadequate. Thank you all. Every one of you contributed in some way to the refinement of these ideas and this text. This may have been my baby, but it had many midwives. Smith received his Ph. Smith has been awarded two U. Prior to that, Dr. Smith spent many years in industry as a physics simulation engineer and consultant building off of dual B. Projects of note included sonar and oceanic environment simulation, electronic engineering simulation, commercial and military aircraft flight simulation, and real-time graphical training systems.
Smith with an opportunity to apply the lessons of SPQR and the EDP catalog and compositional approach to immense bodies of software, both legacy and modern. The history of design patterns is a strange one though, and somewhere along the way, much of their original utility and elegance has been forgotten, misplaced, or simply miscommunicated. This book can fill in some possible gaps for those who have experience with design patterns and can provide students new to the literature a better way of consuming it bite by bite.
When it comes down to it, the design patterns literature as it stands is a collection of rather large nuggets of information of varying degrees of digestibility. This text is a foundation that provides a practitioner familiar with design patterns a methodology for placing those nuggets into a larger system of understanding and provides the student new to design patterns an approach for learning them from basic principles and in smaller pieces that make sense individually.
The Elemental Design Patterns are truly elemental in that they form a foundation for design patterns as a discipline. The collective wisdom of the software engineering community is one of our most valuable assets, and we still have much to learn from each other. This book and the research on which it is based are an attempt to bring to light some of what we have lost regarding design patterns.
Introduction to Design Patterns of design patterns by establishing a better mechanism for shared discussions of patterns, giving us a richer understanding of the software we produce and consume. Our community has produced a breadth of design patterns, but what we lack is depth. That is, we have a broad understanding of wide areas but only a weak ability to stitch them together into a comprehensive whole.
It reminds me of the historical transition from alchemy to modern chemistry—until the periodic table came along, the collective wisdom of many intelligent researchers was precise but not strongly correlated. Gallium and germanium were the first examples of this, with Mendeleev accurately describing their chemical and physical properties well before their discovery. The periodic table advanced chemistry from descriptive discipline to predictive science. The emergence of design patterns within the software engineering community began with the publication of the seminal Design Patterns: Elements of Reusable Object-Oriented Software in Alexander was a civil engineer and architect, and his work focused on finding patterns of solutions to particular sets of forces within particular contexts.
His primary insight was that there are two types of design that occur within architecture, what he named unselfconscious and selfconscious. Unselfconscious design is most often seen in so-called primitive cultures: The design, however, is applied without much, if any, individual discretion or decision making.
Selfconscious design is a more modern invention; the designer is free to make conscious decisions at almost every turn involving style, aesthetics, and materials. This architectural freedom can be seen in the wide array of modern architecture From the Library of Santiago Itzcoatl Salinas Reyna Chapter 1: Introduction to Design Patterns 3 within a given locale, city, or neighborhood.
Even on your own street, you are likely to see a plethora of styles and distinctive flourishes, each the result of many conscious decisions on the part of the architect.
When a designer is freed to do anything, it becomes even harder to pick the effective solutions out of the nearly infinite set of inappropriate or just plain bad ones. Building codes are one way we try to limit the bad choices in housing design, but even given those as a starting point, the task is daunting. Merely reading building codes and adhering to them is not going to produce an effective work of architecture.
Building codes are generic, but good architecture takes into consideration the environment at every level of detail, from global latitude and regional weather patterns to local soil grades and site-specific terrain or foliage. You can see the results of this selfconscious design in almost any town or city.
One house may be Georgian, one pseudo-Victorian, another a modern glass and steel box, or perhaps a split-level, a ranch, or any other number of styles, kinds, and types of construction, materials, and architectures. We have to ask ourselves, however, whether these designs work as optimal, or even just effective, solutions for that particular environment, for that particular context.
Austin, Texas, for example, may not be the best place to build an unshaded glass-faced edifice because the sun is so intense in the summer, creating an added expense from the large increase in cooling costs. Upstate New York may not be an appropriate place for a flat roof because the weight of many feet of snow in the dead of winter adds a significant load to the room beams.
The environmental context, the set of forces that create the situation in which the general problem of designing appropriate housing must be solved, is frequently ignored, and the solutions are generally only minimally satisfying or give rise to new problems that must be addressed. It should be apparent how this applies to software engineering: This is the amazing strength of programming—and its Achilles heel.
We can do just about anything, and usually manage to do so, but unfortunately, the subset of good things out of the set of anything is quite small, and our projects are often late, over budget, and frequently fail in ways spectacular and quiet. Rarely do we walk away from projects with a feeling of accomplishment— more often, we feel we dodged a bullet.
Why is this? Why, when we have decades of collective experience, and quite possibly millions of tallied person-years From the Library of Santiago Itzcoatl Salinas Reyna 4 Chapter 1: Introduction to Design Patterns in the field, are we still thrashing in the weeds every time we approach a problem? Some designers and developers seem to be phenomenally able to sidestep the complexity and find the kernel of effectiveness in a design.
Somewhere in between is a balance to be struck. We need to find the underlying principles and general solutions that exist in unselfconscious architecture and describe them in a way that makes them applicable in a wide variety of contexts selfconsciously and with deliberate intent. The wisdom of the various attempts at solutions, hard-earned through trial and error, need to be distilled into a body of concepts that can be learned by anyone, applied in numerous places, and used as a guide for thinking about design.
This is what design patterns are—the distillation of expertise by an exuberant and robust community. This is crowdsourcing at its best. The patterns community that has grown over the decade-plus since the original GoF work is large and energetic, and our output is voluminous. Grady Booch and Celso Gonzalez have been collecting every pattern they can find in industry and academia at their website .
So far, they have over 2, of them. The quantity of output in this community is huge, and although there are some discussions about the quality, the more pressing problem is one of scale. Even with a fully indexed, well-curated collection of quality design patterns, there is simply too much information for a nonscholar to sift through accurately and quickly.
Worse, it is incredibly difficult for a student wishing to learn the principles behind good design to do so solely from examples of good design. It is a bit like trying to learn the mathematics of aeronautical flow from inspecting aircraft on a runway. What the software development community needs is a more thorough understanding of what it has at its disposal, a methodology that explains how to more precisely describe the existing design patterns and does so using components and well-defined principles that are accessible to the student or new developer.
What we need is a guide to the underlying basic principles of our design patterns literature From the Library of Santiago Itzcoatl Salinas Reyna 1. This book is a foundation for that guide. To put it bluntly, we are mortal, and our young field is aging. Already we have lost a number of luminaries who established the groundwork for our industry, and many more will be gone soon.
It is just a fact of life, one that we are poorly prepared to deal with as a discipline. Worse still, software has a peculiar trait of living long past its expected lifetime.
COBOL is still a force to be reckoned with in business systems around the globe. Currently shipping major high-performance computer systems have code embedded deep in their firmware that was first created three decades or more ago, in assembler or C.
You can be almost certain that somewhere in the millions of lines of implementation that came with your latest personal computer acquisition lies a piece of source code that no person currently understands.
We know we should document our software; we know we should keep it up to date; we know we should commit to pen or screen the whys, the hows, and the reasons; but we also know it is a pain. What we have instead is a body of knowledge that is locked within the heads of developers, that is passed along in fits and spurts, when prompted and only where necessary, frequently without any comprehensive framework of common understanding among stakeholders.
It also has some rather unsettling corollaries. Cultures with a weak discipline for veracity and precision in information transfer leave themselves open to more rapid corruption. A strong oral tradition, however, can result in a very different outcome. The development community has what is ultimately an oral tradition of information transfer. Although we may write down bits and pieces of what we understand, we frequently do not write down the entirety of our comprehension, and we do not keep such documentation in sync with the evolution of our systems.
Introduction to Design Patterns document rot is pervasive, and only by asking around for further information can we hope to fill in the gaps to find out why a particular system is how it is. Until it matters, of course. Agile systems have a funny way of becoming legacy systems, of growing into mature codebases with larger teams that must work in concert. Eventually, code that started as an agile effort, if it is successful, will face many of the same challenges as traditionally developed systems.
Developers leave. Documentation rots. Knowledge is lost. Software as it currently stands is not what anyone could accurately call selfdocumenting, and extracting the salient reasons why a thing was done in a particular way, directly from the source code, has been considered nearly impossible for an automated system. This is unfortunate, because we would like to have our cake and eat it too.
So we punt and hope for the best. Meanwhile, our collective understanding of the system degrades. In the end, what we have is best described as a very weak oral tradition.
Tribal mythology is action without comprehension. It is rote without any foundation on which to state why. Other indications that tribal mythology is active in a group include the following: Over time, this lack of understanding breeds a great deal of uncertainty and fear of change. Unfortunately, it is at some level the status quo on most projects, which is ironic given that our industry is driven by innovation, change, and advancement of the state of the art.
Tribal wisdom, however, is the virtuous flip side of this tribal mythology. It is prescribed action with understanding, how accompanied by why, and is adaptable From the Library of Santiago Itzcoatl Salinas Reyna 1.
It transcends rote copying, and provides illumination through a comprehensive discussion of the reasons behind the action. At some point in the past, for almost every action or decision in a system, someone knew why it was done that way.
Carrying those decisions forward, even the small ones, can be critical. Small decisions accrete into large systems, and small designs build into large designs.
By ensuring that we have a strong tradition of knowledge retention that facilitates understanding, we build a tradition of tribal wisdom. Tribal wisdom is what design patterns were intended to collect. Sadly, they are frequently mis treated as tribal mythology, by applying the how without a clear comprehension of the why.
Recently my wife and I bought our first house, and with it, our first yard. The region we live in is renowned for its rain and consequently its moss. Now, I like moss. It satisfies all the usual requirements for a yard, with less work than grass requires, but we had an odd situation. Part of the yard is heavily shaded and rarely, if ever, sees sun. This area is basically solid moss, with no grass or any other vegetation.
Twenty feet on either side of the heavily shaded portion, however, sunlight is available on most days when the sun is actually out.
Moss grows in patches through this section, but in my initial assessment, I thought it was fine. In the sunniest areas, there was almost no moss but lots of grass. In the shadiest areas, there was solid moss but no grass. In the transitional regions, the two coexisted. What could be better? Unfortunately, long-time residents who saw this situation were horrified. This was less than optimal. To make matters worse, as is the case in many software projects, I had inherited a situation in which I had no idea what the previous residents had done for maintenance in the yard or why.
There was no documentation to indicate what I should do for my lawn or why the yard had been left in this configuration. Introduction to Design Patterns experiments. In the shadiest areas, I pulled up a small section of moss and seeded it with grass. In the rest of the yard, I let the moss go to see what would happen. The grass seed in the shadiest area never thrived. Some sprouted, but it could never get established well.
Applying the tribal mythology would have resulted in bare dirt in a good section of my yard, and frankly, I prefer the moss to that. It is green and lush, and it thrives in that area without maintenance. For that specific area, moss is a good ground cover solution.
In the rest of the yard with little or no shade, it turns out that moss and grass do play well together, more or less. Unfortunately, the moss has a side effect. In the sunniest areas, the moss acts as a protective layer for weeds to sprout underneath, safe from birds and mice who would eat the seeds or shoots, and properly moist. By letting the moss exist in the sunny areas, I was giving weeds a nursery to get established, and when they penetrated the moss, they thrived in the sunlight and spread rapidly.
The moss also provided a protective moist layer for the roots of weeds to travel along, offering them an unhindered growth channel. Within a couple of months, I was fighting a literal turf war with the weeds. The moss was never a problem by itself, but it set the scene for a much larger one.
And now I know the why behind removing moss from a lawn. Essentially, the moss creates a new set of forces at play that form a new context. Within that new context, that new environment, new problems arise—like weeds. Now the advice to remove the moss makes sense, at least for areas where weeds are an issue, such as the sunny areas of my yard. Because I know the why, I can now alter my application of this knowledge according to the environmental forces.
In the sunny areas, I must remove and prevent the moss so that weeds are not a later problem. What was initially tribal mythology is now tribal wisdom that can be shared, adjusted, and applied when and where appropriate.
In essence, it is the beginning of a pattern. There is no doubt that patterns are a thriving meme, and one with great utility.
Tools exist to produce, display, generate, and extract patterns. Patterns, as a collective whole, are an assumed component of the software engineering landscape. Two issues prevent a more comprehensive approach to patterns, and unfortunately they are ubiquitous in the industry.
The first is treating patterns as frozen elements to be blindly copied, the second is confusing language-specific pattern implementations with variants of the patterns themselves. Patterns are intended to be mutated, to be warped and molded, to meet the needs of the particular forces at play in the context of the problem, but all too often, a developer simply copies and pastes the sample code from a patterns text or site and declares the result a successful application of the pattern.
This is usually a recipe for failure instead of a recipe for producing a good design. We undermine the entire purpose of design patterns when we do that. We need to be able to describe the whys behind a pattern as well as the hows. Without the understanding of the reasons that led to the description of that pattern, rote application often results in misapplication. At best, the result is a broken pattern that simply does not match the intended outcome.
At worst, it injects an iatrogenic pattern into the system— one that is intended and thought to be of benefit but instead produces a malignant result that may take years to uncover.
This is patterns as tribal mythology—action without understanding. Introduction to Design Patterns The traditional design pattern form, as defined in Design Patterns , explains the whys behind a pattern—motivations, applicability, and consequences—but it is up to the reader to tease out the underlying concepts that form a pattern.
To some degree, these subconcepts are described in the Participants what are the pieces and Collaborations how do they relate sections for each patterns, but again, these are frequently treated by developers as checklists of pieces of the solution for rote implementation instead of as a description of the underlying concepts and abstractions that comprise a solution.
Different languages offer different strengths centered around the concepts they support and how they express them. How those concepts happen to be expressed is more often the start of flame wars between language fans, but ignoring the underlying concepts leads to much argument over nothing of particular consequence in most cases.
What this means is simply that some patterns are easier to implement in some languages than in others. The Visitor pattern is a good example.
In fact, some programming languages support it directly CLOS, for example. For a language feature? In most other languages, however, Visitor provides a clean way of expressing the same programming concept of double dispatch. This illustrates an important point. If you mention double dispatch instead of the Visitor pattern to the same CLOS developers, they would know what you mean, how to use double dispatch, and when not to use it.
Terminology, particularly shared common terminology, matters a great deal. No language can really be considered superior to another in this case, however. Design patterns describe useful concepts, regardless of the language used to implement them. Whether a specific concept is baked into the feature set of a language or must be implemented from scratch is irrelevant. The concept is still being expressed in the implementation, and that is the critical observation that lets us talk about software design independently of software implementation.
Design is concepts; how those concepts are made concrete in a given language is implementation. This sounds like a lot of work, but these were concepts considered so important that they launched a revolution in language features to make them easier to work with. That revolution was object-oriented programming. In object-oriented languages, those concepts are included as primary language features called classes, visibility, and constructors.
Again, we can refer to the GoF: And yet again, this is a fundamental point that seems lost on most developers, so let me restate it. Patterns are language-independent concepts; they take form and become concrete solutions only when you implement them within a particular language with a given set of language features and constructs. Some design patterns are unique to specific languages, and only those languages, but those patterns are often called language idioms.
In this text when we use the term design patterns, we are specifically talking about concepts that are language independent. Introduction to Design Patterns difference between patterns as expressed in Java and those expressed in another language such as Smalltalk. The concepts are the same; only the manner in which they are expressed and the ease with which a programmer can implement them in that specific language differ.
We need to focus on these when investigating design patterns, and these abstractions must be the crux of understanding patterns. Unless we make the effort to look at patterns as language-independent concepts, we are merely learning rote recipes again and losing much of what makes them so useful. We have an art. What we need is a science. After all, we throw around the terms computer science and software engineering with abandon.
Treating patterns as sample code misses the point of design patterns. Design patterns enable us as an industry to experiment with those concepts and share, discuss, and refine our findings. Patterns as rote recipes are tribal mythology. Patterns as concepts are the foundations of a science. Elemental Design Patterns are the building blocks of that science. Two traits make them unique: First, they are written in the style of the design patterns literature. Each is treated as a standalone concept with a specific name by which it can be discussed and mulled over until it is understood.
This book presents each EDP along with a problem that it is suited for and discusses when the pattern should and should not be applied. You will find example implementations, comments on possible consequences of using the patterns, and related patterns that you should look at as well. This humanoriented definition of each EDP provides you with a common term you can use to clearly and precisely converse with other students or developers about the concept.
Second, design patterns are descriptions of solutions to common problems that were found through the examination of existing software systems.
EDPs are also solutions to common problems, and once you know what to look for, you will find them everywhere.
They are in fact so common that, until now, they have not been considered worth writing up in any comprehensive way. EDPs were originally identified as a comprehensive body of interrelated design concepts not in software but in a formal description of software. Elemental Design Patterns of object-oriented languages, but rest assured, with the exception of an appendix safely tucked in the back, this text is mathematics free.
The solid yet simple ideas underlying the EDPs provide a strong framework on which to revisit these basic concepts, give them new life, and repurpose them for new applications. This foundation also gives you a compelling ability to use them as tiny building blocks, almost like atoms, to describe other design patterns in solid and direct ways. And, like atoms, you can build worlds with them.
This book gives you some background on EDPs, where they came from originally, and how they fit into the larger context of design patterns in programming. It also gives you just enough of a taste of object-oriented theory to understand how the patterns all relate to one another, but no equations, I promise.
We discuss some of the ideas underlying the basics of object-oriented programming, much of which you may already be familiar with. Finally, you learn how that basic theory gives rise to a veritable stable of concepts that you can use in your everyday programming. Later chapters explain how you can use EDPs to make your designs better.
SPQR is a research project for identifying instances of known design patterns within an existing body of source code. It can find design patterns independent of the original source code language and can easily find various implementations of the same design pattern from a single pattern definition. I was inspired to create SPQR while working as a professional software engineer.
I was on a team responsible for one of three libraries used in a real-time commercial and military flight simulation system. In one of our joint all-library development meetings with the application team, they thanked us profusely for a feature we had just added, stating that it was exactly what they needed. After the meeting, the three library teams looked at each other and asked if the others knew what the application team had been talking about. Nearly developer hours later, we had our answer.
We had an instance of a Decorator pattern, one of the Gang of Four GoF patterns, embedded and hidden within the system. Pieces of it were scattered across the three libraries, and the application team had stumbled onto their integration as a whole. We were stunned. A rather heated debate ensued: Was this really a design pattern? Well, most software does just that. It grows organically, and often in unexpected ways. In managing software projects, we can only manage what we know, and knowing that there was this useful design element provided us an opportunity to enhance, streamline, and document its existence for developers to use effectively.
Finding it—that was the problem. Remember, we had written the software in question, we were the experts, and it still took us an inordinate amount of time to deduce what was going on. Automation of the process was the obvious answer. As I mentioned in Chapter 1, what we really want is self-documenting code, or at least a system to extract that documentation. SPQR is such a system. Creating SPQR necessitated solving a fundamental problem: I had to teach the computer how to identify design patterns.
Patterns are not rote recipes; they are soft and amorphous things we humans call concepts. Most research and industry systems that attempt to find instances of patterns in source code do so by looking at patterns as constructs—as rigid forms that look like implementations—rather than as abstract concepts. This is a reasonable approach, and it treats patterns as many developers do: The thing is, this approach once more reduces the design patterns to specific implementations.
Every variation of a possible implementation requires a new definition. These tools are stellar examples of the approach and are worth your investigation. They do their job well, and they add value if you happen to meet their requirements. The problem with this approach is that defining a pattern for queries as a construct is highly fragile. None of these conditions would be found by a construct-oriented approach to From the Library of Santiago Itzcoatl Salinas Reyna 16 Chapter 2: Elemental Design Patterns design patterns, and they would require new pattern definitions.
Remember, patterns are implementation-language independent—the scope of the issue is much larger. It seemed obvious that a different tactic was needed with SPQR. Diving into the background and history of design patterns yielded the necessary clue.
As I read his first and, at least within the software engineering community, least-cited treatise on design patterns, Notes on the Synthesis of Form , I realized something important had been lost: This simple truth fundamentally alters what I was trying to teach the computer to recognize. Teaching a computer system to look for language constructs bolted together in rigid structures will never give us the flexibility we desire with the accuracy we need.
Unfortunately for this particular task, the established design patterns literature is primarily geared toward describing high-level, abstract concepts, which is part of what makes them so powerful—they lift the discussion of a design to a higher level of abstraction.
Programmers generally have a good working handle on lowerlevel abstractions, so establishing them as patterns has never seemed necessary. The design patterns community is rightly focused on documenting those lessons that are not already ingrained and well understood. These design patterns described by the software community tend to be at the larger end of the spectrum. Computers, on the other hand, are fundamentally only as knowledgable as the foundation we can teach them.
For SPQR, we had to establish a chain of concepts from the ground up so it could help us deal with the concepts of programming. We had to fill in the gap between the highly rigid pieces of an implementation and the sometimes fluid concepts that they represent.
In doing so, it became apparent that the EDPs were just that—design patterns that form a fundamental basis from which to describe software design not just for automated analysis but for humans as well.
This book is a partial catalog of the EDPs written for human, not machine, consumption. It is intended to be used by developers, students, and designers to help fill in the gaps in our understanding and our language when discussing software design. As expected with design patterns, each EDP has an informal write-up, or pattern specification, to use an accepted term, and also has an origin as a mathematical construct. This latter trait makes the EDP catalog unique. This brings us to two ways of describing EDPs: The following section intertwines the two while keeping the formalisms to a minimum.
What do we do when faced with a large and gnarly task in computer science? We break it down. Deconstructing the design patterns literature is not a simple thing. A few attempts have been made over the years [12, 17, 32, 40, 41, 43], but they have been partial deconstructions, seen as oddities or curiosities by most developers and researchers outside the immediate field. After all, these smaller deconstructed pieces and concepts are obvious, right? They are basic concepts, basic things we deal with every day, so why bother describing what we already feel we know?
Someone who was trained in functional programming in ML understands recursion very differently from someone whose primary background is C. The two developers will have different assumptions about recursion, where it is useful, and how it should be applied, even though the basic underlying problem that it is solving is the same. Given the discussion of housing styles in Chapter 1, this idea should start to sound familiar.
I said earlier in this chapter that the lower-level concepts of programming have not been a primary target of the design patterns community because the literature is aimed at documenting concepts that are neither ingrained nor well understood. Elemental Design Patterns The low-level concepts we use in programming are unselfconscious, as Alexander defined it. Most of us never study the principles underlying those concepts, but they exist and are well understood at a mathematical level.
In a nutshell, EDPs are the underlying core concepts of programming and software design that have remained mostly undescribed. Those that have been described have not been related to one another in a meaningful and wellfounded manner until now.
Each EDP is a selfconscious description of a core concept. The EDP catalog as a whole relates the EDPs to one another to form a conceptual framework that the student or developer can use to understand other patterns. It provides a taxonomy and lexicon for describing higher-level abstractions, homogenizing the language and abstractions such that when any two developers reference, for example, the EDP Extend Method, they both have a precise understanding of a common definition.
EDPs provide a language with which to reason about, describe, and discuss software, from the most fundamental levels on up. Mainstream design patterns have done an amazing job of providing this knowledge base for the seasoned pro, but until now, no one has aimed that same tool at the novice or student in a comprehensive way.
So how far can we deconstruct these concepts from the design patterns literature? Types and classes in examples are capitalized and set in monotype font. Code examples use the same system.
In general, Decorator is a popular and commonly used design pattern that provides a mechanism for behavior to be extended dynamically at runtime. You can think of it as an internal plug-in or extension system, like you would find in a web browser. Suppose you want to decompose Decorator to better understand it. It is, after all, a rather high-level abstraction.
If you can absorb smaller pieces individually, you can almost certainly have an easier time understanding the pattern. You can download one, put it in your garage, break out the tools, and disassemble the whole car, or you can learn about the pieces individually.
You can study the internal combustion engine, for instance, or the hydraulic braking system. Those systems can be further broken down into parts that you can investigate one by one to make the larger study task easier. In the end, if you know how a gasoline engine works, you not only have the facility to comprehend that portion of the race car as a unit, as an encapsulated abstraction, but you can apply that knowledge to other vehicles, or even lawnmowers, generators, and any other gasoline-engine-driven machine.
Decomposing design patterns serves a similar purpose: After an exhaustive search of the existing literature on design patterns and remember, there are thousands , you might notice that Decorator shares similarities with two other patterns.
One is Objectifier, first described by Walter Zimmer in , shown in Figure 2. Objectifier describes a way for a single object interface to represent multiple From the Library of Santiago Itzcoatl Salinas Reyna 20 Chapter 2: When a client requests a method to be invoked through the Objectifier interface, it does not know which of the two or more concrete method bodies is executed. Object Recursion chains together two objects with related types. Looking at the UML diagrams in Figures 2.
Although they are not exactly the same, certain features in their structure of the UML are similar enough that we can describe parts of Decorator in terms of these other patterns—we can say that Decorator is composed of these patterns.
A closer look shows that Objectifier can be considered a part of Object Recursion. Object Recursion uses Objectifier as the backbone of its form, but it adds a link between one of the concrete implementations and the interface, and it does From the Library of Santiago Itzcoatl Salinas Reyna 2. In other words, when the Initiator class calls handleRequest , by the intent of Objectifier, either the Terminator or Recursor class might handle it.
If Terminator handles it, the request is complete. If Recursor handles it, an additional call is made through the interface for another handleRequest , and the process starts over again. This chain continues until Terminator is the handler, at which point the chain, unsurprisingly, terminates. We should have a better decomposition to work with, but at least we know that patterns can be described in terms of smaller patterns.
What is the smallest deconstructed pattern we can make that is still a pattern? To answer that question, we need to ask again, What is a pattern? We know it is a concept, we know it is an element of design, and we know has certain critical components. Design is the manner in which parts of a whole interact with and relate to one another, as illustrated in the outline of a design pattern written in the accepted canonical format popularly described in the GoF text. Consider a common definition of design pattern: The structure, implementation, and sample code are unmistakably the solution.
The intent, motivation, and known uses describe the problem space. Elemental Design Patterns Table 2. They describe the parts and their relationships that lie at the intersection of the three arms of a design pattern. Relationships form the core of design. The design of a car is more than a pile of pieces: A house is more than a stack of lumber, a case of nails, and some copper piping; it has a form, or plan, that fights entropy and, we could say, keeps the structure at a higher energy level than just a rubble pile.
The parts list ensures that you have everything you need to begin building, but the relationships in the design tell you how to make them work in concert. What is the smallest relationship we can define? Well, that one is easy. A single relationship between two things is simplest.
Now we can apply this insight to the deconstruction of design patterns. This gives us a clear goal. Well, not all relationships are created equal. Some are quite important when discussing design, and some are there to provide a context. The primary contextual relationship is that of scoping, and it appears in many forms.
The scope is how that element is made unique from all others in the system. Their scope indicates that they are distinct classes, never to be confused. This principle applies any time there is an enclosing something that has a name and within which you define something new. Classes are scopes for the methods and fields they define.
Namespaces and packages are scopes for anything inside of them. Methods and functions are scopes for the local variables declared within them. Over and over again we see the same mechanism at work in many different language features. To access a specific element, we state precisely which one we want by providing the scopes from the top down. Sometimes these scopes are implicit, and we can leave them off, such as when referring to a local variable within a method or to another member within a class.
Furthermore, despite their common behavior, these scopes can have different syntaxes through which they are accessed. Menu, using a double colon.
Given an instance of that class, however, we would access its list of menu items as aMenu. Both of these techniques specify which element we wish to select from a scoping element, but they do so in different ways. This text defines a single way in which we can treat all scoping, regardless of how it is implemented for specific language features within specific languages. A has a field b of type B. In the main body, an instance a of type A is instantiated, and then a.
The method f is scoped by the object a. In object-oriented languages, functions and methods are always enclosed by some scope, even if the scope is implicit. Check Clause 3. Elemental Design Patterns Listing 2. Again, objects are being used to scope and wrap elements that have previously been considered as freely roaming.
Getting back to the code example, a. The relationship between a and f, one of enclosure or scoping, is contextual. It helps specify which method we are talking about. A similar relationship exists between b and g. The call from a. Scoping relationships help us refine our view to a particular design element. We need exactly two such design elements to form the single relationship described in an EDP.
There may be a number of scoping relationships that set up the final single relationship we are interested in, but we are not immediately concerned with them. They are part of the description of the elements of programming that comprise the endpoints of the relationship we wish to work with. Returning to our earlier metaphor of housing styles and design, the scoping elements are a bit like stating that a piece of wood is a two-by-four or a half-inch-thick sheet of bias-grain plywood.
Now we just have to determine what a relationship of interest is. What remains are classes, their fields and methods, and little else. One item seems to be missing from the list: It is object-oriented programming, after all! For a formal explanation, see the appendix.
For now, we have these four kinds of programmatic entities on our list: This may seem like an odd thing to do, but it actually makes solid sense. A class is an interesting beast in that it is so common in most object-oriented languages that many students and developers consider it a primary and necessary element. The reality, from a strictly object-oriented viewpoint, is that it is not. Instead, they rely on prototyping, cloning, and other actions on objects to perform the same functions.
Even Smalltalk, arguably the progenitor of most object-oriented languages, has a quite different implementation and understanding of a class even though the same term is used. First, it describes the elements that will be in instantiated objects of that class, the member methods and fields. Most of us expect a class to be used in this way. Second, it describes elements that are common across all instantiated objects of that class, the class methods and fields.
The first use case corresponds directly to a type in the formal sense, and the second use case can From the Library of Santiago Itzcoatl Salinas Reyna 26 Chapter 2: Notice that in main the use of the class field sharedField is prefaced by the class name MyClass.
This is exactly the same notation used to access aField in the defined myNamespace.
We provide the name of the object and the piece we want selected out of it, just like any object that was instantiated from a class in the normal way. When the language provides a namespace, a package, or a class, it is providing a way of instantiating these objects automatically. Still not convinced?
In Smalltalk, the class is represented by an object. Literally, it is named the class object. Class methods and fields live in that class object. It is almost exactly the scenario we are describing here. Or, look at Java. In Java the class object is a special object that is available for inspection through reflection and is associated with a class that a developer defines.
Listing 2. Although the details of how it is handled will differ from language to language, in every case a class can be emulated using a type and an object. While this may sound a bit foreign to you at first, it quickly becomes second nature in practice. Any defined class members would be moved into a corresponding class object, as in Smalltalk, or into the reflection-accessed Java class object.
We needed types in order to satisfy basic properties of typed languages, and objects are the core of object-oriented languages regardless of their class features. By using these two in conjunction, we can emulate classes from class-based objectoriented languages. This allows us to simplify our set of items needed to define design patterns to just our four previously mentioned items: In what ways can the items on this short list interact? Table 2. Methods can, in some languages, similarly define, or scope, inner methods or types, and of course we can define local variables or fields.
Methods can also call other methods, use nonlocal fields, and have a return type. Fields are simpler in that they can be assigned the return value of a method or of another field. And, of course, they have a type. Not that many interactions are possible now, which means that we can start enumerating them into a finite and, better yet, quite small set of possibilities. A field has a type on which it relies; this is simply the type of the field.
The same holds for objects. Similarly, methods have return types. They are used to define what a piece of data is, whether it is a field or another object such as a parameter or a return value from a method. Much like scoping, defining data has the feel of describing the object or field itself, not providing a relationship between two entities.
For instance, look at the code snippet in Listing 2.
The data member pos is defined as being an instance of the type Position. Similarly, the types of the parameters to the scaleCopy method only tell us what those parameters are, not how they relate to anything else. On the other hand, other relationships, such as a type relying on another type, provide more information than just a description of one element. We might even say it is ingrained and understood. For the purpose of defining the EDPs, there are only the four basic relationships left in the center of Table 2.
As shown in the preceding tables, we can call these a method call, a field use, a state change, and cohesion. Believe it or not, nearly this entire book concentrates on just the first one, a method call reliance. Yes, there is a lot to be said about a simple method call reliance when looked at in the right light.
It has probably occurred to you that a method call looks an awful lot like a structural entity, not a conceptual one. Consider a method f that calls method g in its body. We say that f relies on g. Now assume that g in turn calls another method h, as in Listing 2.
We say that g relies on h. It should be self-evident that this relationship is transitive—if f relies on g, and g relies on h, then f also relies on h. If we want f to rely on h, does it matter if it is a direct method call or if method g is in the middle? It does not. As long as f relies on h by some path, our requirement holds true. We just made the leap from a structural connection, that of a method call, to a conceptual connection, that of a method call reliance.
This frees us from having to discuss low-level programming concepts of design in a structural manner and enables us to describe them in the conceptual way outlined earlier as necessary for working with and finding design pattern instances with SPQR. We discuss this in more detail and show how it forms a critical portion of working with EDPs in Chapter 4, Section 4.
In the process of teaching SPQR about programming concepts, we made the transition away from rigid structures of programming and instead gained a From the Library of Santiago Itzcoatl Salinas Reyna 30 Chapter 2: By using these same techniques ourselves, we provide developers and designers with the same flexible thinking and ability to abstract design from implementation in a methodical yet understandable manner.
We get double duty out of the same approach. We have reduced our list of interesting elements of programming to just four: We concentrate almost exclusively on the method—method reliance in this book. Can this one reliance, based solely on method calls, really do anything useful to help us describe the larger design pattern literature? Given the right context, anything is possible. We focused on primary reliances such as those between methods and fields, bypassing other kinds of relationships, such as type—type reliances or inheritance.
For a given method call reliance, there are three other pieces of information we can work with to help us figure out what the purpose of that reliance is in a particular design. In more pure languages such as Java, you cannot; each method must be in an object, either as an instantiation of a class or as a static class-level method, which is equivalent to placing the method with the class-object for that class. For any given method call reliance, then, there are four pieces: Figure 2.
These pieces are present in every method call. The three pieces of information hiding in plain sight are: The similarity between the enclosing objects 2. The similarity between the types of the enclosing objects The 3. Colloquially, it means what you think— a resemblance between two things. But what does it mean in the context of method call reliance?
Elemental Design Patterns Object similarity is the extent to which one object is like another. Is it the same object? Is it an alias to the second object through a pointer?
Is it completely unrelated?
We can also discuss the similarity of relationship between the types of the objects. Are they the same type? Is one a subtype of the other? Or maybe one is a sibling type of the other, with a common supertype ancestor? Method similarity is a bit trickier. We need to determine whether two methods are trying to do a similar task. We could look at many aspects: There is a much easier way, however, if we take a page from social engineering and look at the method names and, to a lesser extent, the method signatures.
No, really. Think about it for a moment. The name. The first is to name the method after how it accomplishes its task. This is hard work, especially when you only have a single implementation. The resulting code will be easier to read and more flexible.