460 likes | 507 Views
Design Patterns. Software Design and Development. Outline. Definition and Description of a Design Pattern Discussion of Selected Patterns Kinds of Patterns Reference: Gamma et al (“Gang-of-4”), Design Patterns. Pattern.
E N D
Design Patterns Software Design and Development
Outline • Definition and Description of a Design Pattern • Discussion of Selected Patterns • Kinds of Patterns Reference: Gamma et al (“Gang-of-4”), Design Patterns
Pattern • Describes a problem that has occurred over and over in our environment, and then describes the core of the solution of that problem in a way that the solution can be used a million times over, without ever doing it in the same way twice.
Design Pattern • Solution to a particular kind of problem • How to combine classes and methods • Not solve every problem from first principles • Based on design experience • Use requires understanding of the appropriate problem and being able to recognize when such problems occur • Reuse solutions from the past
Describing a Pattern • Name • Intent/Problem • Situation (problem) and context • When to apply the pattern; conditions • Solution • Elements that make up the design, relationships, collaboration; more a template rather than a concrete solution • How the general arrangement of elements (classes and objects) solves it • UML diagrams (class relationships and responsibilities) and code implications
Describing a Pattern • Consequences • Results, variations, and tradeoffs • Critical in understanding cost/benefit
How Design Patterns Solve Design Problems • Finding appropriate objects • Determining object granularity • Specifying object interfaces • Specifying object implementations • Putting reuse mechanisms to work • Designing for change
Finding Appropriate Objects • Factors involving decomposition of system into objects (at times in conflicting ways) • encapsulation, granularity, flexibility, performance, evolution, reusability, etc • Different approaches • Problem statement: nouns and verbs translate to classes and operations • Focus on collaborations and responsibilities • Model real world (analysis) and translate to design • Many objects come from analysis model, but often have additional classes in design that have no counterpart in real world
Finding Appropriate Objects • Strict modeling of real world tends leads to system that reflect today’s realities, but not necessarily tomorrow’s • Abstractions that emerge during design are key to making design flexible
Determine Object Granularity • How to decide what should be an object? • Different patterns have different approaches • represent complete subsystems as objects • support huge numbers of objects at finest granularities • create objects whose only responsibility is creating other objects • create objects whose responsibilities are to implement a request on another object or group of objects
Specifying Object Interfaces • Interface: set of operation signatures • complete set of requests that can be made to an object • Does not commit to implementation until run-time • Define interface by identifying key elements and kinds of data that get sent across an interface • Specify relationships between interfaces • require classes with similar interfaces • place constraints on interfaces
Specifying Object Implementations • Defining internal state and implementation of the operation • Class vs Interface inheritance • Class: mechanism for code and representation sharing • Interface: describes when an object can be used in place of another • Distinction important for diff design patterns • Common theme: Variables not instances of concrete classes; commit only to interface defined by an abstract class; use creational patterns to create instances
Reuse mechanisms • Inheritance vs composition • White box reuse: by subclassing • internals of parent visible to subclasses • Black box reuse: assembling or composing objects to get more functionality • Both go together, but there is a tendency to overuse inheritance. Favor composition where possible
Designing for Change • Create objects indirectly instead of using class names (factory, abstract factory, prototype) • Avoid hard coding requests (chain of responsibility, command) • Limit platform dependencies (abstract factory, bridge) • Isolate algorithms that are likely to change (Builder, Iterator, Visitor, …) • Etc
How to select design patterns • Consider how the design patterns solve design problems • Scan intent section • Consider how patterns interrelate • Study patterns of like purpose • Examine cause of redesign • Consider what should be variable in design (what you might want to change without redesign): Encapsulate the concept that varies
How to use a design pattern • Read up on the pattern • Study structure, collaboration, participants • Look at sample code • Choose names of participants meaningful in the application context • Define classes • Define application specific names for operations in the process • Implement the operations
Selected Patterns for Discussion • Singleton • Factory Method • Composite • Iterator
Singleton • Intent • ensure a class has only one instance, and provide a global point of access to it • Motivation • Important for some classes to have exactly one instance. E.g., although there are many printers, should just have one print spooler • Ensure only one instance available and easily accessible • global variables gives access, but doesn’t keep you from instantiating many objects • Give class responsibility for keeping track of its sole instance
Design Solution • Defines a getInstance() operation that lets clients access its unique instance • May be responsible for creating its own unique instance Singleton static uniqueinstance Singleton data static getInstance() Singleton methods…
Singleton Example (Java) • Database public class Database { private static Database DB; ... private Database() { ... } public static Database getDB() { if (DB == null) DB = new Database(); return DB; } ... } Database static Database* DB instance attributes… static Database* getDB() instance methods… In application code… Database db = Database.getDB(); db.someMethod();
Singleton Example (C++) class Database { private: static Database *DB; ... private Database() { ... } public: static Database *getDB() { if (DB == NULL) DB = new Database()); return DB; } ... } Database *Database::DB=NULL; In application code… Database *db = Database.getDB(); Db->someMethod();
Implementation • Declare all of class’s constructors private • prevent other classes from directly creating an instance of this class • Hide the operation that creates the instance behind a class operation (getInstance) • Variation: Since creation policy is encapsulated in getInstance, possible to vary the creation policy • Subclassing: Variable that refers to singleton instance must get initialized with instance of the subclass • use registration
Singleton Consequences • Ensures only one (e.g., Database) instance exists in the system • Can maintain a pointer (need to create object on first get call) or an actual object • Can also use this pattern to control fixed multiple instances • Much better than the alternative: global variables • Permits refinement of operations and representation by subclassing
Abstract Factory • Intent: provide an interface for creating objects without specifying their concrete classes • Example: Stacks, Queues, and other data structures • Want users to not know or care how these structures are implemented (separation) • Example: UI toolkit to support multiple look-and-feel standards, e.g., Motif, PM • Abstract class for widget, supporting class for specific platform widget
Solutions in C++ • Use of header file (class declarations) and implementation file (method definitions) ok but limited • Header file usually contains private declarations which are technically part of the implementation • Change in implementation requires that the application using the data structure be recompiled • Alternative: create an abstract superclass with pure virtual data structure methods
Design Solution for Abstract Factory Factory createProduct() Product virtual methods Client ConcreteProdA methods ConcreteProdB methods Note: this is an abbreviated design
Participants • Abstract Factory • declares an interface for operations that create abstract product objects • Concrete Factory • implements the operations to create concrete product objects • Abstract Product • declares an interface for a type of product object • Concrete Product • defines a product object to be created by the corresponding concrete factory • implements the abstract product interface
Participants • Client • uses only interfaces declared by AbstractFactory and AbstractProduct classes
Stack Example (C++) • Stack class defines virtual methods • push(), pop(), etc. • ArrayStack and LinkedStack are derived classes of Stack and contain concrete implementations • StackFactory class defines a createStack() method that returns a ptr to a concrete stack • Stack *createStack() { return new ArrayStack(); } • Client programs need to be aware of Stack and StackFactory classes only • No need to know about ArrayStack()
Factories in Java • Stack is an Interface • ArrayStack and LinkedStack implement Stack • StackFactory returns objects of type Stack through its factory methods • Select class of the concrete factory it supplies to client objects • If using info from requesting client, can hardcode selection logic and choice of factory objects • Use Hashed Adapter Pattern to separate selection logic for concrete factories from the data it uses to make the selection
Abstract FactoryConsequences • Factory class or method can be altered without affecting the application • Concrete classes are isolated • Factory class can be responsible for creating different types of objects • e.g., DataStructure factory that returns stacks, queues, lists, etc. • “product families”
Abstract Factory Consequences • Promotes consistency among products • When products in a family are designed to work together, it is important that an application use objects from only one family at a time. This pattern enforces this. • Supporting new kinds of products is difficult • requires extending the factory interface (fixed set) • change AbstractFactory class and all the subclasses
Composite Pattern • Intent: compose objects into tree structures to represent (nested) part-whole hierarchies • Clients treat individual objects and composition of objects uniformly • Example: GUIs (e.g., java.awt.*) • Buttons, labels, text fields, and panels are VisualComponents but panels can also contain VisualComponent objects • Calling show() on a panel will call show() on the objects contained in it
Participants • Component • declares the interface for objects in the composition • implements default behavior for interface common to all classes • declares interface for managing and accessing child components • (optional) defines interface for accessing a component’s parent in the recursive structure • Leaf • Leaf objects; primitives; has no children • define behavior for primitive objects
Participants • Composite • Defines behavior of components having children • Stores child components • Implements child-related operations in the composition • Client • manipulates objects in the composition through the component interface
Consequences • Defines class hierarchies consisting of primitive objects and composite objects • Easy to add new kinds of components • Simple client – can treat primitives and composites uniformly
Iterator Pattern • Intent: provide a way to access the elements of an aggregate object sequentially without expressing its underlying representation • Example: iterators of C++ STL containers • Note that you can have several iterator objects for a container and that the iterators are separate classes
Motivation • Take responsibility for access and traversal out of the container object and into an iterator or Cursor object • Example ListIterator List First() Next() IsDone() CurrentItem() index Count() Append(Element) Remove(Element) …
Consequences • Supports variations in the traversal of an aggregate • Simplifies the aggregate interface • More than one traversal can be pending on one aggregate
Kinds of Patterns • Creational • Object creation; e.g., Factory and Singleton • Structural • Object structure; e.g., Composite • Behavioral • Object interaction and distribution of responsibilities; e.g., Iterator
Creational Patterns • Abstract Factory • Builder • Factory Method • Prototype • Singleton
Structural Patterns • Adapter • Bridge • Composite • Decorator • Façade • Flyweight • Proxy
Behavioral Patterns • Chain Of Responsibility • Command • Interpreter • Iterator • Mediator • Memento • And a few more …
Summary • Main point: to recognize that there are proven solutions to problems that a designer/ programmer may encounter • Solutions are results of others’ experiences • Towards “standard approaches” • Search for such solutions first • Although there is some merit attempting to create the solution yourself • Becoming a design architect