Advanced ActionScript 3: Design Patterns, Second Edition (2015)
Chapter 4. Intro to Design Patterns
Although many developers were slow to adopt object-oriented programming (OOP), in the 1990s a handful of computer scientists at IBM were making strides in devising structures based on object-oriented principles. They addressed solutions to reoccurring programmatic issues that decreased the scalability and maintainability of their applications. In their debut book, Design Patterns: Elements of Reusable Object-Oriented Software (Erich Gamma, Richard Helm, Ralph Johnson, and John M. Vlissides; Addison-Wesley, 1994), the so-called Gang of Four demonstrated the practicality of using OOP.
As you saw in Chapter 3, you can determine a list of objects that you may be able to implement into your application. Although analysis reveals such objects, it doesn’t reveal the means by which these objects can collaborate with and message one another in a flexible structure. The many variations among object-oriented languages helps as well as hinders our efforts to architect a flexible structure. You also need a clear understanding of the benefits an object-oriented language provides; hence the inclusion of Chapter 2 in this book.
Without adequate OO knowledge, developers can still use object collaborations, but at the cost of efficiency, possible structural flexibility, and with the potential for personal frustrations.
Not all developers fall victim to such dilemmas. Experienced developers over time have learned numerous techniques they use to combat flexibility issues. As each project changes, such solutions are modified and tweaked to suit the new variations.
At the suggestion of OOP pioneers (James Coplien, for example), many developers have documented the implementations they use to overcome particular problems. This documentation provides a catalog of solutions that overcome the lack of flexibility in the design of collaborative objects.
Design Patterns Catalog
Before ActionScript was a language, the answers to many programmatic challenges had already been tested, refined, solved, and documented. Many of these are probably obstacles you have, at some point, struggled to work around. These issues existed long before you or me and will always remain in this field. This is because change is a constant.
What began as theories and hacks came to be time-tested solutions to reoccurring problems that developers face. These patterns provide solutions to the need for flexibility of behaviors, structure, and creation of collaborative objects in an application.
In most cases, these patterns target the objects themselves, using dynamic binding and polymorphism; others deal with the code that is fixed in classes and their subclasses. Design patterns introduce solutions you may not have previously seen or known about.
In addition to providing solutions, design patterns serve as a language developers can use to describe an arrangement of code. The more familiar you become with specific patterns, the easier it will be to realize how they can help you loosen the couplings between objects and achieve a more reusable, scalable, maintainable system.
Over time, developers are drawn to certain patterns and eventually become so familiar with those patterns that they use them almost without thinking. More important than your affinity for specific patterns is choosing a pattern based on the circumstances, or what the problem dictates. By analyzing the problem at hand, you can arrive at the necessary pattern.
Many patterns have been cataloged according to their purpose, the category to which they pertain, and their name. This book focuses on three categories: creational, behavioral, and structural. The following definitions are from Design Patterns: Elements of Reusable Object-Oriented Software:
Creational patterns abstract the instantiation process. They help make a system independent of how its object are created, composed, and represented.
Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects. They describe not just patterns of objects or classes but also the patterns of communication between them.
Structural patterns are concerned with how classes and objects are composed to form larger structures.
Every pattern has a specific name. This name is the identifier by which a solution is known and referred to by programmers. In the case of a design pattern, the name symbolizes the objects used, the collaboration in which they work, and the behaviors they possess.
Reading a Design Pattern
The football players in Figure 4-1 may be in the right positions, but you can’t tell how they work together to achieve their goal. The simple use of lines and arrows brings the strategy to life, indicating the relationships of the players as shown in Figure 4-2.
Figure 4-1. Representation of a team formation
Figure 4-2. Representation of a team’s strategic game play
A professional developer’s design-pattern books are much like the playbook of a professional team, showing the actions of every athlete on the field. But in the developer’s case, the star athletes are objects.
Why do you need to be able to read a design pattern? Simple. Design patterns aren’t lines of code that can be easily copied and pasted into your application. Instead, they illustrate the means to conquer a specific problem via diagrams like the one in Figure 4-2. As you’ve seen, no two object-oriented languages are the same; and therefore not all implementations are the same, even if the difference is a mere matter of syntax. What does remain the same is the mental model the language mirrors. Think of a design pattern as a seed waiting to blossom with your help.
In order to achieve maximum flexibility, patterns often use added levels of indirection, which can complicate object-oriented designs. Being able to understand the ways in which a pattern is presented can make all the difference in your ability to understand it. They will illustrate the object distinctions and the relationships they possess.
As you may know, Unified Modeling Language (UML) is the tool used to lay out all object-oriented designs. It’s the language spoken between an architect and a developer, and it’s the standard used to represent model-driven architecture.
Having a standard ensures that models can be understood by developers using varying software languages. This is an advantage, because to be adopted by the widest possible audience, patterns should avoid language specifics. To read a design pattern, you need to be able to properly interpret its UML class diagram.
The Class Diagram
The class diagram is the most common form of modeling you’ll see in design patterns. These diagrams, as the name suggests, expose the classes used in a system/subsystem and the relationships among them. Class diagrams don’t show the steps an object takes to message another; sequential diagrams and interaction diagrams illustrate that behavior, which is beyond the scope of this book.
The classes in a class diagram represent specific elements of the system or subsystem used in the pattern. Classes in a design pattern diagram typically expose only the public methods to which another object can message. This is because the diagram is only concerned with exposing aspects that reflect the relationships among the objects, not implementations. However, some attributes are often included to further illustrate object behaviors.
As illustrated in Figure 4-3, attributes and behaviors can be seen following symbols that denote the appropriate visibility of the member.
Figure 4-3. A typical Class Diagram
The objects in each system serve special roles, and their relationships help reveal how they’re used. Some relationships indicate collaborations, some compositions, and some indicate subclasses. The relationships among system classes are represented using association and generalization.
Associations among objects are illustrated by the way objects in a class diagram are connected to each another. The simplest way to indicate a relationship is to draw a line connecting two classes (see Figure 4-4). This is referred to as a common association.
Figure 4-4. Illustrates a common association between Vector.<uint> and GrayScaleHalftone
Although the line signifies the connection between the two classes, the diagram doesn’t specify ownership or the flow of communication between the objects. Some diagrams remedy this lack of specifics by using association roles; to do so, you add text above the association, explaining the relationship. In Figure 4-4, you could identify the objects’ roles by adding uses > above the association, indicating that GrayScaleHalftone uses the vector, and not the other way around.
Often, the line between objects in a diagram is dashed or dotted, representing an object or behavioral implementation:
· Object implementation: A dashed line from one class to another represents the instantiation of an object. The dashed line begins at the object initiator and points to the class that will be instantiated.
· Behavioral implementation: When a behavior supplies a specific implementation, a dashed line flows from the method to a callout that shows the specific behavior.
An aggregated relationship is one in which multiple parts are combined to produce a distinct object. You can think of an aggregation as a “has-a” relationship: the whole is produced by the sum of its parts. The behaviors of the parts aren’t limited to benefitting the whole they help create. An unfilled diamond connecting the whole to a part defines the relationship as an aggregation; it signifies the object’s ability to exist independently of the whole.
An example of aggregation is the relationship of an RSS feed to a blog, where the feed is created from the combination of many articles. Without the articles, the RSS feed can’t exist; but the articles exist independently of the RSS on the blog (see Figure 4-5).
Figure 4-5. An illustration of 3 Generic Articles as an aggregate to some RSS feed
Composition is a type of association in which one or more objects together produce a whole, and exist only to perform behaviors on that whole. Due to this dependence, the parts are meaningless as individual objects outside their roles within the whole. The UML representation of a composition relationship is a solid diamond connecting the part to the whole (see Figure 4-6).
Figure 4-6. House requires a roof, walls, and a ceiling to fulfil the role of a house
The last type of association is generalization, which you can think of as inheritance. The hierarchy among objects is identified by a common association from the subclass to its superclass. An unfilled arrowhead appears at the superclass end of the connecting line (see Figure 4-7).
Figure 4-7. Using a generalized association to an abstract class aThread
Much like a class, an interface’s name appears in the first segment of the UML diagram; its public method is shown in the second segment (see Figure 4-8). The fact that this is an interface is indicated by the interface declaration above the name, prefixed by two left arrows (<<) and suffixed by two right arrows (>>).
Figure 4-8. A defined interface in a class diagram
Many object-oriented languages, including ActionScript 3, don’t support abstract classes. For this reason many class diagrams display an association from an implementation of an object to an interface.
This chapter explained how to approach design patterns as they are documented, and intended for use. We learned that a design pattern is the core of a solution.
No matter what Object-Oriented Language a programmer may use, a solution should be readily available to them by understanding the core of such a solution. A design pattern’s documentation addresses the necessary objects and their associations in a manner that is unspecific to a programming language. Each documentation is noted with the use of the Unified Modeling Language, and, therefore, a programmer should be familiar with UML in order to understand how to read a design pattern, as well as architect his or her own Object-Oriented Designs.
Chapter 4 concludes the discussion of the necessary aspects of Object Oriented Programming and the pre-requisites of the upcoming chapters.
· Design patterns are solutions to common object-oriented design dilemmas.
· Design patterns are divided into three categories: creational, behavioral, and structural.
· Creational patterns abstract the instantiation process.
· Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects.
· Structural patterns are concerned with how classes and objects are combined to form larger structures.
· A common association is illustrated by connecting objects with a thin line.
· Composition is a relationship among objects that share a similar lifeline.
· Aggregation is a whole made up of independent parts.
· Class diagrams, sequential diagrams, and interaction diagrams can be used to design collaborations.
· UML stands for Unified Modeling Language.
· Inheritance can be signified using an interface.
· Design patterns don’t reflect a specific object-oriented language.
Chapter 4 is only an introduction to design patterns. The information here is supported, and reinforced in the chapters thoroughly discussing design patterns, Chapters 6-8. After this chapter, you will be able to test your knowledge from the first four chapters before proceeding to Chapters 6-8.
I encourage you to read these chapters in order, because the discussion of one pattern may reference a previous pattern. All the examples have been written to best illustrate how a design pattern appears in an actual application. As you read the code for each example, remember that patterns shouldn’t be taken at face value; the code that illustrates each pattern is intended to solve an issue particular to the example. Remember, a design pattern suggests how to solve a common dilemma; it doesn’t show you specifically how it should be implemented in every scenario.