Download presentation
Presentation is loading. Please wait.
1
Design Patterns
2
Patterns 1, 2, 3, … is a sequence that exhibits the pattern:
The integers in their natural order
3
Another Sequence 1, 3, 5, … The pattern: The odd integers, in order
4
What is a Pattern? A template or model for imitation A set of rules
A dress pattern A cookie cutter As we shall see, an object-oriented design diagram A set of rules For the Fibonacci sequence, the rule is: the ith element (except for f0 and f1) is equal to the sum of the (i-1)st element and the (i-2)nd element.
5
Why are Patterns Useful?
Patterns describing infinite sequences eliminate having to enumerate all values 0, 1, 1, 2, 3, 5, 8, … Don’t have to list all the elements
6
Why are Patterns Useful?
A pattern can be a convenient membership test for a set of elements Regular expressions denote patterns of strings For example [a-zA-Z][a-zA-z0-9]* is a pattern representing identifiers Compilers use regular expressions to test for identifiers
7
Why are Patterns Useful?
Knowledge of a pattern can enable one to easily produce new objects:
8
Why are Patterns Useful?
In particular, patterns discerned from existing situations may be applied to new situations a, b, c, … Monday, Tuesday, Wednesday, …
9
But Sometimes the Similarities are not Obvious
10
Patterns and Abstraction
Which Bring Us To… Do 1, 2, 3, … and Monday, Tuesday, Wednesday, … exhibit the same pattern?
11
Patterns and Abstraction
1, 2, 3, … the integers in their natural order Monday, Tuesday, Wednesday, … the days of the week in their natural order Are these the same pattern?
12
Patterns and Abstraction
The pattern we really mean is The elements of some sequence taken in their natural order What about the fact that the integers are infinite and the days of the week are finite?
13
Some Patterns are Simple…
ABC Jackson 5 Michael: you went to school to learn, girl Things you never, never knew before... … … Jermaine: sit yourself down, take a seat All you gotta do is repeat after me. J5: a b c Michael: easy as... J5: Michael: or simple as... J5: do re mi Michael: abc, 123, baby, you and me girl!
14
Others are Less Obvious…
2, 3, 5, 7, … primes March, April, June, … Months without a ‘Y’ in their names in natural order Mensa likes to use patterns like these as part of their qualification test
15
Some are Quite Difficult…
6, 28, 496, … perfect numbers e, t, a, … most frequent letters in the English language in descending order
16
… And Some are Just Downright Ornery
Especially if they’re not mathematical and you don’t know the context 214, 232, 234, … Classrooms on 2nd floor of New Ingersoll from east to west 1110, 2210, 3110, … For cryin’ out loud– you’re CIS majors!
17
Patterns Within Patterns
B C
18
And Now For Something Completely Different… Summing Integers Read from a File
cin >> i; while (i >= 0) { total += i; }
19
Finding the Maximum Double in a File
cin >> d; while (cin) { if (d > max) max = d; }
20
Building a String from a Line of Characters
c = getchar(); while (c != ‘\n’ && c != EOF) s[i++] = c; } s[i] = ‘\0’;
21
Three Individual Pieces of Code…
Different datum types int, double, char Different end-of-input conditions negative datum, end-of-file, end-of-line/end-of-file Different tasks: summing, maximum, string construction
22
… and Yet A Pattern Emerges
In all three cases: Values are read from a file A condition is used to test for end-of-input The values are processed in some fashion A ‘priming-the-pump’ technique is used
23
An Input Loop Pattern read first item while (still more items) {
process item read next item }
24
Why Are Such Patterns Useful?
Avoids ‘reinventing the wheel’ Avoids making the same mistakes over and over again Speeds up the development process ‘Reusability’ of sorts
25
Design Patterns Pattern concept applied to software design
Not a finished product Reuseability of design ‘ideas’ Many patterns crop up over and over again
26
A Non-Software Example- Flywheel
A flywheel is a massive rotating disk The basic idea is to accelerate the flywheel to a very high speed and thus maintain the energy as rotational energy using the disk.
27
Flywheel - Samples
28
Why a Flywheel? In the 70’s engineers were looking for a low-emissions, non-internal-combustion vehicle. Wanted to be able to ‘charge’ the vehicle and have it store that charge Charging involved bringing the flywheel up to a high speed Batteries were too bulky, heavy Would need tens of batteries for a small vehicle
29
Flywheel – Useful For Storing kinetic energy – often in a fairly small space Maintaining a uniform force. Production of high power pulses Can also be used to create a form of gyroscopic effect
30
Flywheel – Advantages Not affected by temperature changes
No limit to energy stored Simple to measure stored force (measure rotation speed)
31
Flywheel – Disadvantages
Danger of explosive shattering of wheel
32
Flywheel – Parts Massive wheel Axle Bearings
33
Flywheel - Applications
Low-cost toys (the kind you wind up by running the wheels along the floor) Energy-efficient cars (during braking, surplus energy is used to accelerate the flywheel which can subsequently power the driveshaft) Used on satellites to point the instruments in correct direction Potters wheel
34
Flywheel - Summary Note the variety of applications
Yet all use the same basic design pattern
35
Flywheel - Summary Notice what we did here
Provided a motivational situation (low-emission vehicle) Presented the purpose of the flywheel Described when to use one Presented the parts of the flywheel Discussed advantages and disadvantages Gave known applications Presented some samples
36
A Simple Software Example
You’ve got a program from CISC 3130 (Data Structures) Written in C++ Uses a stack class template Which you wrote (whole point of assignment) Massive application Hundreds of modules Thousands of lines of code Ok, Ok, two hundred lines of code in one file Stack usage scattered throughout system
37
Our Simple Software Example
After CISC 3130, you learn about the STL (Standard Template Library) Library of useful data structures, including those you learned in 3130 You decide you want to play with it Good to know for a tech interview So you toss out your stack and begin using the one from the STL
38
There’s a mismatch in the interfaces
The Problem Your stack’s operations: push – places argument on top of stack pop – pops stack returning value isEmpty – true if empty STL’s stack’s operations: push – same peek – returns top of stack pop – pops stack, no value returned empty – different name, same semantics There’s a mismatch in the interfaces
39
Solution #1 Change the application code to conform to the new operations
40
The Changes Replace and s.pop(); // yours Global edit replace?
s.isEmpty(); // yours with s.empty(); // STL’s and s.pop(); // yours s.peek(); // STL’s s.pop(); Global edit replace?
41
??? !!! #^%$!!! Scratch that solution!! void clear() {
while(!s.isEmpty()) s.pop(); } void clear() { while(!s.empty()) s.peek(); s.pop(); } #^%$!!! Scratch that solution!!
42
So?? What’s Plan B?
43
Plan B Add a new class, StackAdapter
StackAdapter declares a member variable of type stack (from the STL). StackAdapter defines functions corresponding to the ones in your original stack class Some of the functions do nothing more than call corresponding functions of the STL stack Other functions act as adapters between the old and new semantics
44
The StackAdapter Class
template <class E> class StackAdapter { public: push(E val) {s.push(val);} E pop() { E x = s.peek(); s.pop(); return x; } bool isEmpty() {return s.empty();} private: stack<E> s;
45
The Adapter Pattern Plan B employs a design pattern known as Adapter
Converts the interface of a class into another interface clients expect. Adapter lets classes work together that otherwise couldn’t because of incompatible interfaces
46
The Adapter Pattern Visually
StackAdapter push() pop() isEmpty() x = s. pop() s.pop(); return x; s.isEmpty() s Stack push() pop() empty()
47
You May Have Seen Something Similar
For example, when coding binary search… The recursive call for binary search is bool binsrch(int a[], int lo, int hi) … but the user wants to make the call bool binsearch(int a[], int n) We resolve this by adding an intermediate function: bool binsearch(int a[], int n) { return binsrch(a, 0, n-1); } This is the a procedural analogy of the Adapter pattern; binsearch is usually called a wrapper function.
48
Design Patterns Introduced by architect Christopher Alexander (A Pattern Language: Towns, Buildings, Construction) in the context of buildings and towns: “Each pattern describes a problem which occurs over and over again in our environment, the describes the core of the solution to that problem, in such a way that you can use the solution a million times over, without ever doing it the same way twice.”
49
Architectural Design Patterns
“A PLACE TO WAIT” Bus stop Waiting room adresses the common aspects of their design “ARCADES” - “covered walkways at edges of buildings, partly inside, partly outside”
50
‘The Gang of Four’ Book Introduced design patterns to software design
Much of this talk based upon this text In fact, it’s fair to say that one purpose of this talk is to provide a guide to how to read this text Bulk of text is a catalog of patterns
51
Why Only ‘Object-Oriented’?
Wouldn’t this have been useful before as well? ‘Designing object-oriented software is hard, and designing reusable objected-oriented software is even harder’ (Opening sentence of ‘Design Patterns’, Gamma, et al) The number and complexity of classes, objects and their interactions makes proper design a formidable task Also, might have been applicable before, but OOP (compared to say, procedural) ‘maxes’ out on reusability More opportunities for reuseable design Everybody says that, but let’s see why
52
OOP and Reusability So WHAT makes objected-oriented software more reusable than say applications designed and coded in a procedural style? Classes? Inheritance Overloaded operators? Access control?
53
Reusability Mechanisms – Inheritance
Allows one class to incorporate (reuse) another class’s implementation as part of its own All state (variables) and behavior (functions) of the existing (super/base/parent)class become part of the new (sub/child)class. Subclass can then add its own state/behavior The subclass is said to be a subtype of the superclass’ type Not available in traditional procedural languages
54
Reusability Mechanisms - Inheritance
class Counter { Counter() {val = 0;} void up(val++;} void down() {val--;} int get() {return val;} int val; } class BoundedCounter extends Counter { BoundedCounter(int m) { max = m; } void up() { if (val < max) val++; int max;
55
Reusability Mechanisms - Composition
Assembling or composing objects to get new functionality Basically one class contained as a variable of another Reusability comes from The containing object (re)using the functionality of the contained object(s) … and thus avoiding implementing that behavior on its own Somewhat available in traditional procedural languages
56
Reusability Mechanisms - Composition
class SSNum { boolean equals(SSNum other) { … } class Employee { boolean equals(Employee other) { return id.equals(other.id); } … SSNum id;
57
Reusability Mechanisms - Delegation
One object carries out a request by delegating it to a second object (typically an instance variable of the first) Used widely in the context of composition, especially as a way of obtaining some of the flavor of inheritance In the previous example, the Employee object delegated the equality test to the (composed) Name object. Somewhat available in traditional procedural languages
58
Reusability Mechanisms - Interfaces
A set of function signatures (no bodies) Can be thought of as representing a type Can be specified in C++ via abstract classses and in Java via interfaces. A class (i.e., with function bodies) is said to implement the interface if the class defines (I.e., supplies bodies for) all the interface’s functions As with inheritance, the implementing class is also said to be a subtype of the interface’s type Not available in traditional procedural languages
59
Reusability Mechanisms - Interfaces
interface Collection { boolean add(Object obj); boolean remove(Object obj); int size(); boolean isEmpty(); }
60
The Is-a Relationship An object of a subtype is compatible with the corresponding (parent) type. The object of the subtype is considered an object of the type as well This is known as the ‘is-a’ relationship… … and is the basis for much of the reusability of OOP
61
‘Is-a’ in the Context of Inheritance
An object of a subclass is compatible with the parent class’ type Thus given a Counter variable, a BoundedCounter object can be assigned to that variable: BoundedCounter bctr; Counter ctr = bctr;
62
‘Is-a’ in the Context of Interface
An object of a class implementing an interface is compatible with the interface’s type Thus assuming Set implements the Collection interface. given a Collection variable, a Set object can be assigned to that variable: Set set; Collection coll = set;
63
So What??? Given an interface, Collection, write a method, contains that returns true if a specified object belongs to a specified collection. boolean contains(Collection coll, Object obj) { for(Object element : coll) if (element.equals(obj)) return true; return false; } contains can accept (as the coll parameter) a Set, a Vector, in fact any class that implements the Collection interface. Only one contains function need be written for a whole family of different (though related by the Collection interface) aggregate classes
64
So What II??? The similarity of classes conforming to an interface provides the opportunity for them to employ the same pattern/solution to a problem Providing a solution in the form of an interface (i.e., a set of methods) in turn provides a solution for ANY class that implements that interface. Implementing that interface means that the solution is available For example, the constructor that accepts a Collection can be used by all Collection classes since it employs only methods specified in the Collection interface and thus us available to all Collections!
65
Describing Design Patterns
Recall our Flywheel In addition to presenting the flywheel we also presented Motivation Purpose Application Advantages/disadvantages
66
Describing Design Patterns
Design Patterns are presented in a similar (fairly standardized) fashion
67
Pattern Description - Name
Name should be a good reflection of the pattern’s purpose Adapter
68
Pattern Description - Intent
A statement answering: What does the pattern do? What is its rationale? What problem does it address? Adapter converts the interface of a class into another interface clients expect. Adapter lets classes work together that otherwise couldn’t because of incompatible interfaces
69
Pattern Description – Also Known As
Other names by which the pattern is known Wrapper
70
Pattern Description – Motivation
A scenario that illustrates the problem and its solution via the classes and structures of the pattern Our CISC 3130/STL Stack problem and solution
71
Pattern Description – Applicability
Under what circumstances can the pattern be applied? What are examples of poor designs that the pattern can address? How can such situations be recognized? Use Adapter when: You want to use an existing class and its interface does not match the one you need
72
Pattern Description – Structure
A graphical representation of the relationships among the classes/objects in the pattern Client Target Request() Adaptee SpecificRequest() Class Interface Implemented method() Abstract method() Adapter Request() adaptee method pseudo-code adaptee.specificRequest() Instance variable subtype
73
Pattern Description – Participants
The classes and objects participating in the pattern Target (the interface consisting of push, pop, isEmpty) Defines the specific interface that Client uses Client (Your 3130 program) Interacts with objects conforming to the Target interface Adaptee (STL stack type) Defines an existing interface that needs adapting Adapter (StackAdapter) Adapts the interface of Adaptee to the Target interface
74
Pattern Description – Collaborations
How the participants interact to realize the pattern Clients call operations on an Adapter object In turn the adapter calls Adaptee operations
75
Pattern Description – Consequences
What are the trade-offs and results of using the pattern? How much adapting does Adapter do? Simple name changes all the way to supporting completely different set of operations There are several other consequences we won’t address here
76
Pattern Description – Implementation
Pitfalls, hints, techniques? Language-dependent issues? Fairly straightforward There are some language issues, but again, not for now
77
Pattern Description – Sample code
We’ll just let our example be the sample code
78
Pattern Description – Known uses
Examples from real systems Take a look at Gamma
79
Pattern Description – Related Patterns
What other patterns are closely related to this one? What are the similarities? Differences? Which patterns use this pattern? Which patterns does this pattern use? This was our first one! Too early to supply answers for this
80
Why are Design Patterns Useful?
Avoids ‘reinventing the wheel’ Avoids making the same mistakes over and over again Knowledge of a particular design pattern (like Adapter) is valuable… … but so is simply knowing about the concept of a design pattern Knowing there are catalogs of patterns addressing design issues Gets you thinking about design problems differently
81
Another Example Adapter was an example of a Structural design pattern
Structural patterns are concerned with how classes and objects are composed to form larger structures. Our next example will present a Creational design pattern Creational patterns help make a system independent of how its objects are created and represented.
82
Another Example Us folks at Provide interactive programming exercises
Students submit solution code to our server which Does operational and textual checks Provides feedback In addition, there is a context-sensitive glossary/help system Generates hypertext links into the glossary, ‘on-the-fly’, for instructions and feedback
83
Creating a Glossary Object
Glossary glossary = new Glossary(); Issues Glossary is quite large – one is OK, but what if there are tens (or hundreds) of concurrent users? No need for more than one glossary It’s a query-only object
84
Creating a Glossary Object
Is there a way to prevent more than one Glossary object from being created? The expression glossary = new Glossary() creates a new instance each time And if we can restrict to one instance, how does the rest of the application access that single instance? C++ could use a global variable (but how would we know where it is?) What about Java?
85
Singleton Design Pattern - Intent
Ensure a class has only one instance and provide a global point of access to it
86
Singleton - Motivation
Just gave it to you, but since you asked Ensuring single print spooler in a system Ensuring a single buffer/node pool
87
Singleton - Applicability
Used when There must be exactly one instance, which must be accessible from a well-known point
88
Singleton - Structure Singleton static instance() singletonOperation()
getSingletonData() static uniqueInstance singletonData return uniqueInstance
89
Singleton - Participants
Defines an instance operation that allows clients to access its unique instance instance is a class (i.e., static) function/method May be responsible for creating its own unique instance
90
Singleton - Collaborations
Clients access a Singleton instance solely through the instance operation
91
Singleton - Consequences
Controlled access to single instance Reduced name space No global variables Can permit variable number of instances I lied– it’s actually one glossary per language glossary = new Glossary(“Java”)
92
Singleton - Implementation
class Glossary { public static Glossary getGlossary() { if (glossary == null) glossary = new Glossary(); return glossary; } private Glossary(); private Glossary glossary; Note the private Glossary constructor
93
Singleton – Implementation Multiple Instances
class Glossary { public static Glossary getGlossary(String language) { Glossary glossary = map.get(language); if (glossary == null) { glossary = new Glossary(language); map.put(language, glossary); } return glossary; private Glossary(String language); private Map<String, Glossary> = new HashMap<String, Glossary>; Note the private Glossary constructor
94
Behavioral Patterns Structural and creational patterns are two of the three pattern purposes, the third being behavioral patterns Behavioral patterns are concerned with algorithms the assignment of responsibilities between objects the patterns of communication between objects/classes characterize complex control flow We’ll now present Observer, a behavioral pattern which is probably one of the most elegant patterns of all
95
This is not Your Father’s Oldsmobile
On a typical mid-to-high-end car these days rain sensors turn on the wipers wipers turn on the lights shifting out of park turns on day running lights turning on radio raises antenna pressing brake disengages cruise control and a host of other interactions between sometimes seemingly unrelated components
96
One Particular Set of Interacting Components
Let’s focus on just three components The interior light The interior light switch Turning to ‘on’ turns on the interior light The car door Opening turns on the interior light
97
Let’s Code a Car Class class Car { … // Instance variables
Door door = new Door(); InteriorLightSwitch interiorLightSwitch = new InteriorLightSwitch(); InteriorLight interiorLight = new InteriorLight(); }
98
The InteriorLight Class
class InteriorLight { public boolean isOn() {return amOn;} void setOn(boolean b) { if (amOn != b) { amOn = b; System.err.println("interior light turned “ + (amOn ? "on" : "off")); } boolean amOn = false;
99
The InteriorLightSwitch Class
class InteriorLightSwitch { public boolean isOn() {return amOn;} void setOn(boolean b) { if (amOn != b) { amOn = b; System.err.println("interior light switch “ + “moved to “ (amOn ? "on" : off")); interiorLight.setOn(amOn); } boolean amOn = false;
100
The Door Class class Door { public boolean isOpen() {return amOpen;}
void setOpen(boolean b) { if (amOpen != b) { amOpen = b; System.err.println("door " + (amOpen ? "opened" : "closed")); interiorLight.setOn(amOpen); } boolean amOpen = false;
101
Who should know when to turn on the interior light?
Mind Your Own Business Door knows it should turn on light Interior switch knows it should turn on light An alarm module (keyless entry) would also have to turn on light Who should know when to turn on the interior light?
102
More Issues In ‘luxury’ model opening door causes seat to slide back
Now door must know to turn on light and slide seat back But what about non-’luxury’ cars? Separate door mechanism for luxury/non-luxury? Luxury/non-luxury models ‘wired’ differently?
103
‘Spaghetti’ Responsibility Logic
Turning on wiper switch Must know to turn on wipers Wipers in turn must know to turn on headlights and activate 4WD sensor Headlights must know to dim radio display
104
‘Spaghetti’ Responsibility Logic
Pressing brake Turns on ‘upper rear brake light’ Turns on brake lights Disengages cruise control, but only if that option is present Initiates ALB sensor
105
‘Spaghetti’ Responsibility Logic
Every component must know about all components dependent upon it Furthermore, every component becomes responsible for those components
106
Well how about if I tell you that our implementation is wrong?
Still Not Convinced?? Well how about if I tell you that our implementation is wrong?
107
A Sample Car interaction
public static void main(String [] args) { Car car = new Car(); car.door.setOpen(true); System.err.println(car); car.door.setOpen(false); System.err.println(car); car.interiorLightSwitch.setOn(true); System.err.println(car); }
108
The Output door opened interior light turned on (as a result of opening the door) door: opened / interior light: on / interior light switch: off door closed interior light turned off (as a result of closing the door) door: closed / interior light: off / interior light switch: off interior light switch moved to on interior light turned on (as a result of turning the switch on) door: closed / interior light: on / interior light switch: on door opened (no light action -- light already on) door: opened / interior light: on / interior light switch: on interior light turned off (as a result of closing the door – but the switch is still on!) door: closed / interior light: off / interior light switch: on
109
OOP = Responsibility-Driven Programming
Goal is for objects (components) to be responsible for themselves ‘Decoupling’ objects simplifies the design The simpler, more self-responsible objects are easier to reuse
110
The Observer Design Pattern - Intent
Define a (many to one) dependency between objects so that when one object changes state, all its dependents are notified and updated automatically
111
Observer - Applicability
Use Observer when either A change to one object requires changing others, and you don’t know how many others need to be changed An object should be able to notify other objects without making assumptions about who those objects are (minimize coupling between the objects)
112
Observer - Structure from Wikipedia
113
The Observer Interface
interface Observer { void notify(); } An Observer’s notify method is called (by the Subject object) when the Subject object has changed.
114
The Observable Superclass
class Subject { void registerObserver(Observer observer) { observers.add(observer); } void notifyObservers() { for (observer : observers) observer.notify(); Set<Observer> observers = new HashSet<Observer>();
115
The InteriorLight Class
class InteriorLight implements Observer { InteriorLight(InteriorLightSwitch interiorLightSwitch, Door door) { this.interiorLightSwitch = interiorLightSwitch; this.door = door; interiorLightSwitch.registerObserver(this); door.registerObserver(this); } public boolean isOn() {return amOn;} private void setOn(boolean b) { if (amOn != b) { amOn = b; System.err.println("interior light turned " + (amOn ? "on" : "off")); public void notify() { setOn(interiorLightSwitch.isOn() || door.isOpen()); boolean amOn = false; InteriorLightSwitch interiorLightSwitch; Door door;
116
The InteriorLightSwitch Class
class InteriorLightSwitch extends Subject { public boolean isOn() {return amOn;} void setOn(boolean b) { if (amOn != b) { amOn = b; System.err.println("interior light switch “ + “moved to " + (amOn ? "on" : "off")); notifyObservers(); } boolean amOn = false;
117
The Door Class class Door extends Subject {
public boolean isOpen() {return amOpen;} void setOpen(boolean b) { if (amOpen != b) { amOpen = b; System.err.println("door " + (amOpen ? "opened" : "closed")); notifyObservers(); } boolean amOpen = false;
118
The Output This Time door opened interior light turned on
door: opened / interior light: on / interior light switch: off door closed interior light turned off door: closed / interior light: off / interior light switch: off interior light switch moved to on door: closed / interior light: on / interior light switch: on door: opened / interior light: on / interior light switch: on interior light switch moved to off
119
Minimizing Hard-coding
The CodeLab engine can check exercises for any language that has a compiler An appropriate set of tools and entities– compilers, linkers, compiler message analyzers, glossaries – must be created specific to the language We want this done without hard-coding any knowledge of particular languages into the engine This is accomplished using the Factory Method pattern
120
Maintaining Consistency
Furthermore, the language-specific tools used in an exercise must be consistent with each other (i.e., be restricted to tools of that specific language). This is addressed using the Abstract Factory pattern This design was introduced into the engine by Josh Goldsmith as part of his 88.1 project.
121
Invoking the Tools Many of the tools used to build and test exercises form tree-like hierarchies of sorts Java Tool C++ Tool Java Compiler Tool C++ Compiler Tool Java Interpreter Tool C++ Linker Tool Executable Tool A Java Tool is executed by executing a Java Compiler Tool followed by executing a Java Interpreter Tool Similarly for the C++ Tool
122
Treating Individual Objects and Compositions Identically
Sometimes a full Java Tool is launched Other times simply the Java Compiler Tool We want to launch and subsequently process both tools (the composite Java Tool and the atomic Java Compiler Tool) identically This is achieved using the Composite pattern
123
Filtering Streams When processing submissions and exercise output, we often want to Remove whitespace completely Remove a final trailing linefeed Compress multiple whitespace to a single whitespace Remove comments Ignore case This is done using the Strategy pattern
124
Iteration Any class implementing the Collection interface must supply a uniform means of iterating over its elements. This is done via the Iterator pattern
125
Whew! In summary Design patterns provide highly flexible, reusable solutions to commonly arising design situations Patterns are recognized as valuable repositories of information based upon analysis and experience Catalogs exist enumerating collections of patterns Conscious use of patterns is widespread
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.