Unit IV: GoF Design Patterns Objects Design means Object identification and their relationships, how they interact with each other. (Blue print of the problem, that shows objects and their relationships) Designing Objects With Responsibilities “Identify requirements, create a domain model and define dynamic behaviour , define messages to meet requirements , add methods to the software classes …” Too Simple! How do we assign responsibilities to classes? What methods belong where? 6 Object Design : Input • Use case text – Defining the behavior • System sequence diagram – Identifying the system operation messages • The operation contract – Stating events to design for, and detailed post-condition to satisfy • Supplementary specification – Defines non-functional goals • Glossary – Data format, data related with UI and database • Domain model – initial attempt of software object in the domain layer of software architecture 7 Responsability Driven Design-RDD Design of behavior implies assigning responsibilities to software classes. Responsibilities are assigned to classes of objects during object design. Responsibility is a contract or obligation of a class – What must a class “know”? [knowing responsibility] – What must a class “do”? [doing responsibility] 8 Doing Responsability What must a class “do”? [doing responsibility] Take action (create an object, do a calculation) Initiate action in other objects Control/coordinate actions in other objects Doing responsibilities are implemented by means of methods Methods fulfill responsibilities alone or through collaboration with other objects and methods. Ex: A Sale is responsible for creating SalesLineItems” (doing) 9 Responsibilities and methods : create : Sale makePayment(cashTendered) create(cashTendered) abstract, implies Sale objects have a responsibility to create Payments Sale objects are given a responsibility to create Payments. The responsibility is invoked with a makePayment message : Payment knowing responsibility What must a class “know”? [knowing responsibility] Knowing responsibilities are related to attributes, associations in the domain model. Domain model illustrates attributes and associations => inspires the “knowing” responsibilities. Ex : a Sale is responsible for knowing its total” (knowing) 11 Responsibilities and attribute getDueDate message implies Book has responsibility for knowing its due date. d := getDueDate() :Book 12 RDD and Collaboration Responsibilities are implemented by methods. Some methods act alone and do a task. Some collaborate with other objects to fulfill their responsibility. Example: Sale class has getTotal() method, the getTotal() collaborates with SalesLineItem objects to get the subtotal through getSubtotal() methods 13 Well‐known Pattern Families GRASP = General Responsibility Assignment Software Patterns Describe fundamental principles for assigning responsibilities to classes and for designing => interactions between classes GoF: Gang of Four Design Patterns : 23 pattrens We’ll cover with GOF 14 Definitions • A pattern is a recurring solution to a standard problem, in a context. • “A pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.” -by Christopher Alexander, a professor of architecture… Software pattern What is a software pattern? A design pattern is a general reusable and proven solution to a commonly occurring problem in software design. “ a pattern is a named problem/solution pair that can be applied in new contexts, with advice on how to apply it in novel situations” -by Craig Larman: 16 The “gang of four” (GoF) • • • • Erich Gamma Richard Helm Ralph Johnson John Vlissides The “gang of four” (GoF) – Design Patterns book catalogs 23 different patterns as solutions to different classes of problems, in C++ & Smalltalk – The problems and solutions are broadly applicable, used by many people over many years – Patterns suggest opportunities for reuse in analysis, design and programming – GOF presents each pattern in a structured format Elements of Design Patterns • Design patterns have 4 essential elements: – Pattern name: increases vocabulary of designers – Problem: intent, context, when to apply – Solution: UML-like structure, abstract code – Consequences: results and tradeoffs Three Types of Patterns • Creational patterns (5): – Deal with initializing and configuring classes and objects • Structural patterns (7): – Deal with decoupling interface and implementation of classes and objects – Composition of classes or objects • Behavioral patterns (11): – Deal with dynamic interactions among societies of classes and objects – How they distribute responsibility Creational Patterns • Abstract Factory: – Factory for building related objects • Builder: – Factory for building complex objects incrementally • Factory Method: – Method in a derived class creates associates • Prototype: – Factory for cloning new instances from a prototype • Singleton: – Factory for a singular (sole) instance Structural Patterns • Adapter: – Translator adapts a server interface for a client • Bridge: – Abstraction for binding one of many implementations • Composite: – Structure for building recursive aggregations • Decorator: – Decorator extends an object transparently • Facade: – Simplifies the interface for a subsystem • Flyweight: – Many fine-grained objects shared efficiently. • Proxy: – One object approximates another Behavioral Patterns • Chain of Responsibility: – Request delegated to the responsible service provider • Command: – Request or Action is first-class object, hence re-storable • Iterator: – Aggregate and access elements sequentially • Interpreter: – Language interpreter for a small grammar • Mediator: – Coordinates interactions between its associates • Memento: – Snapshot captures and restores object states privately Behavioral Patterns (cont.) • Observer: – Dependents update automatically when subject changes • State: – Object whose behavior depends on its state • Strategy: – Abstraction for selecting one of many algorithms • Template Method: – Algorithm with some steps supplied by a derived class • Visitor: – Operations applied to elements of a heterogeneous object structure GoF Design Patterns If you aren't an experienced object-oriented designer, then start with the simplest and most common patterns: – – – – – – – – Adapter (Structural pattern) Factory(Creational pattern) Singleton(Creational pattern) Strategy(Behavioral pattern) Composite(Structural pattern) Façade(Structural pattern) Observer (Behavioral pattern) Command (Behavioral pattern) Describing Design Patterns • Pattern Name and Classification • Intent – A short statement that answers the following questions: • What does the design pattern do? • What is its rationale and intent? • What particular design issue or problem does it address? • Also Known As – Other well-known names for the pattern, if any. • Motivation – A scenario that illustrates a design problem and how the class and object structures in the pattern solve the problem. The scenario will help you understand the more abstract description of the pattern that follows. • Applicability – What are the situations in which the design pattern can be applied? – What are examples of poor designs that the pattern can address? How can you recognize these situations • Structure – A graphical representation of the classes in the pattern using a notation based on the Object Modeling Technique (OMT) [RBP+91]. We also use interaction diagrams [JCJO92, Boo94] to illustrate sequences of requests and collaborations between objects. • Participants – The classes and/or objects participating in the design pattern and their responsibilities. • Consequences – How does the pattern support its objectives? What are the trade-offs and results of using the pattern? What aspect of system structure does it let you vary independently? • Implementation – What pitfalls, hints, or techniques should you be aware of when implementing the pattern? Are there language-specific issues? • Sample Code – Code fragments that illustrate how you might implement the pattern in C++ or Smalltalk. • Known Uses – Examples of the pattern found in real systems. We include at least two examples from different domains. • Related Patterns – What design patterns are closely related to this one? What are the important differences? With which other patterns should this one be used? Adapter Pattern (26.1) Problem: How to resolve incompatible interfaces, or how to provide a stable interface to similar components with different interfaces. Solution: Convert the original interface of a component into another interface, through an intermediate adapter object. Note: the Adapter pattern is an application of Polymorphism Adapter Pattern (26.1) Example: POS needs to adapt several kinds of external third-party services: tax calculators, credit authorization services, inventory systems, accounting systems. Each has a different API which can’t be changed. Fig. 26.1 Adapters use interfaces and polymorphism to add a level of indirection to varying APIs in other components. «interface» ITaxCalculatorAdapter getTaxes( Sale ) : List of TaxLineItems TaxMasterAdapter GoodAsGoldTaxPro Adapter getTaxes( Sale ) : List of TaxLineItems getTaxes( Sale ) : List of TaxLineItems «interface» IAccountingAdapter postReceivable( CreditPayment ) postSale( Sale ) ... «interface» ICreditAuthorizationService Adapter requestApproval(CreditPayment,TerminalID, MerchantID) ... «interface» IInventoryAdapter SAPAccountingAdapter postReceivable( CreditPayment ) postSale( Sale ) ... GreatNorthernAccountingAdapter postReceivable( CreditPayment ) postSale( Sale ) ... ... Fig. 26.2 :Register : SAPAccountingAdapter makePayment ... SOAP over HTTP postSale( sale ) xxx «actor» : SAPSystem the Adapter adapts to interfaces in other components Adapter Pattern (26.1) Note: Adapter pattern follows GRASP principles: Polymorphism, Protected Variation, Indirection See Fig. 26.3 for conceptual connection among GRASP principles and Adapter pattern Fig. 26.3 Low coupling is a way to achieve protection at a variation point. Protected Variation Mechanism GRASP Principles Polymorphism is a way to achieve protection at a variation point, and a way to achieve low coupling. An indirection is a way to achieve low coupling. Low Coupling Mechanism High Cohesion Mechanism Indirection Mechanism Pure Fabrication The Adapter design pattern is a kind of Indirection and a Pure Fabrication, that uses Polymorphism. Polymorphism Example Adapter GoF Design Patterns Factory Pattern (26.4) Problem: Who should be responsible for creating objects when there are special considerations such as complex creation logic, a desire to separate creation responsibilities for better cohesion, etc.? Solution: Create a Pure Fabrication object called a Factory that handles the creation. Factory Pattern (26.4) • A variation of GoF Abstract Factory pattern Fig. 26.5 ServicesFactory accountingAdapter : IAccountingAdapter inventoryAdapter : IInventoryAdapter taxCalculatorAdapter : ITaxCalculatorAdapter note that the factory methods return objects typed to an interface rather than a class, so that the factory can return any implementation of the interface getAccountingAdapter() : IAccountingAdapter getInventoryAdapter() : IInventoryAdapter getTaxCalculatorAdapter() : ITaxCalculatorAdapter ... if ( taxCalculatorAdapter == null ) { // a reflective or data-driven approach to finding the right class: read it from an // external property String className = System.getProperty( "taxcalculator.class.name" ); taxCalculatorAdapter = (ITaxCalculatorAdapter) Class.forName( className ).newInstance(); } return taxCalculatorAdapter; Factory Pattern (26.4) Note: In Fig. 26.5 the implementation of ServicesFactory illustrates data-driven design – a form of Protected Variation Factory Pattern (26.4) Idea: Define an object whose purpose is to create objects Benefits: – Separate the responsibility of complex creation into cohesive helper objects – Can provide object caching (e.g. having only one random number generator) Singleton Pattern (26.5) Problem: Exactly one instance of a class is allowed. Objects need a global and single point of access. Solution: Define a static method of the class that returns the singleton: getInstance() Singleton Pattern (26.5) Consider the factory and how it is accessed – who creates the factory? – Only want one instance of the factory – Methods may need to be called from various places => how to make single instance of the factory globally visible Could pass the ServicesFactory instance around as a parameter whenever visibility is required or initialize all objects that need it with a permanent reference to it Singleton – supports global visibility or a single access point to a single instance Fig. 26.6 UML notation: this '1' can optionally be used to indicate that only one instance will be created (a singleton) 1 ServicesFactory UML notation: in a class box, an underlined attribute or method indicates a static (class level) member, rather than an instance member instance : ServicesFactory singleton static attribute accountingAdapter : IAccountingAdapter inventoryAdapter : IInventoryAdapter taxCalculatorAdapter : ITaxCalculatorAdapter getInstance() : ServicesFactory getAccountingAdapter() : IAccountingAdapter getInventoryAdapter() : IInventoryAdapter getTaxCalculatorAdapter() : ITaxCalculatorAdapter ... // static method public static synchronized ServicesFactory getInstance() { if ( instance == null ) instance = new ServicesFactory() return instance } singleton static method Singleton Pattern (26.5) Note: concurrency control in ServicesFactory – making getInstance() synchronized Fig. 26.8 shows how Adapter, Factory, Singleton patterns are used in design Fig. 26.8 1 :Store :ServicesFactory create create :Register accountingAdapter = getAccountingAdapter create : SAPAccounting Adapter accountingAdapter: SAPAccountingAdapter :Register makePayment create(cashTendered) : Payment SOAP over HTTP postSale( sale ) xxx «actor» : SAPSystem Singleton pattern (creational) • Ensure that a class has only one instance and provide a global point of access to it – Why not use a global variable? class Singleton { public: static Singleton* getInstance(); protected: //Why are the following protected? Singleton(); Singleton(const Singleton&); Singleton& operator= (const Singleton&); private: static Singleton* instance; }; Singleton *p2 = p1->getInstance(); Strategy Pattern (26.7) Problem: How to design for varying but related algorithms or policies? How to design for the ability to change these algorithms or policies? Solution: Define each algorithm/strategy in a separate class with a common interface Strategy Pattern (26.7) Example: How to provide more complex pricing logic, e.g. store-wide discount, senior citizen discount, employee discount, etc. A pricing strategy for a sale can vary, how do we design for these varying pricing algorithms? Fig. 26.9 «interface» ISalePricingStrategy getTotal( Sale ) : Money PercentDiscount PricingStrategy AbsoluteDiscount OverThreshold PricingStrategy percentage : float getTotal( s:Sale ) : Money ... discount : Money threshold : Money getTotal( s:Sale ) : Money { return s.getPreDiscountTotal() * percentage } ??? PricingStrategy { pdt := s.getPreDiscountTotal() if ( pdt < threshold ) return pdt else return pdt - discount } ... Strategy Pattern (26.7) Example: Create multiple SalePricingStrategy classes each with a polymorphic getTotal() operation Note: each getTotal() operation takes a Sale object as a parameter so that the strategy object can find the prediscount price from the Sale The implementation of each getTotal() will differ A strategy object is attached to a context object – the object to which it applies the algorithm, e.g. Sale Fig. 26.10 s : Sale lineItems[ i ] : SalesLineItem :PercentDiscount PricingStrategy t = getTotal loop { t = pdt * percentage } st = getSubtotal t = getTotal( s ) pdt = getPreDiscountTotal note that the Sale s is passed to the Strategy so that it has parameter visibility to it for further collaboration Strategy Pattern (26.7) Example: – When a getTotal() message is sent to a Sale it delegates work to its strategy object – It is common for the context object to pass a reference to itself to the strategy object so that the strategy object has parameter visibility to the context object Fig. 26.11 Sale needs attribute visibility to its Strategy Sale date ... getTotal() ... 1 pricingStrategy getTotal() { ... return pricingStrategy.getTotal( this ) percentage : float } getTotal( Sale ) : Money PercentDiscount PricingStrategy «interface» ISalePricingStrategy getTotal( Sale ) : Money AbsoluteDiscount OverThreshold PricingStrategy discount : Money threshold : Money getTotal( Sale ) : Money Strategy Pattern (26.7) Example: Who should create the strategy? – Apply the Factory pattern: a PricingStrategyFactory – The PricingStrategyFactory is a singleton and accessed via the Singleton pattern Fig. 26.12 1 PricingStrategyFactory instance : PricingStrategyFactory getInstance() : PricingStrategyFactory getSalePricingStrategy() : ISalePricingStrategy getSeniorPricingStrategy() : ISalePricingStrategy ... { String className = System.getProperty( "salepricingstrategy.class.name" ); strategy = (ISalePricingStrategy) Class.forName( className ).newInstance(); return strategy; } Fig. 26.13 1 :Register :PricingStrategyFactory makeNewSale create :Sale ps = getSalePricingStrategy create(percent) ps : PercentDiscount PricingStrategy Strategy Pattern (26.7) Note: – Strategy is based on Polymorphism and provides Protected Variation with respect to changing algorithms – Strategies are often/usually created by a Factory Composite Pattern (26.8) Problem: How to treat a group or composition structure of objects the same way (polymorphically) as a non-composite (atomic) object? Solution: Define classes for composite and atomic objects so that they implement the same interface. Composite Pattern (26.8) Design problem: How to handle multiple conflicting pricing policies? Example: – – – – 20% senior discount Preferred customer discount of 15% off sales over $400 On Monday, there is a $50 off purchases over $500 Buy one case of Darjeeling tea, get 15% discount off everything Composite Pattern (26.8) Example (cont.): Pricing strategies determined by – Time period (Monday) – Customer type (senior) – Line item product (Darjeeling tea) In addition to pre-discount price • May have multiple co-existing strategies • Customer type and type of product may need to be known at time strategy is created (i.e. known by StrategyFactory) Composite Pattern (26.8) Example (cont.): Now how do we design so that the Sale object does not know if it is dealing with one or many pricing strategies and also offer a design for the conflict resolution Composite pattern! Composite Pattern (26.8) Key feature: – The composite object contains a list of inner objects and both the composite object and the inner objects implement the same interface Fig. 26.14 { ... return pricingStrategy.getTotal( this ) } All composites maintain a list of contained strategies. Therefore, define a common superclass CompositePricingStrategy that defines this list (named strategies). Sale date ... 1 «interface» ISalePricingStrategy pricingStrategy getTotal( Sale ) : Money getTotal() ... PercentageDiscount PricingStrategy AbsoluteDiscount OverThreshold PricingStrategy 1..* strategies Composite PricingStrategy percentage : float getTotal( Sale ) : Money discount : Money threshold : Money add( ISalePricingStrategy ) getTotal( Sale ) : Money getTotal( Sale ) : Money { return sale.getPreDiscountTotal() * percentage } CompositeBestForCustomer PricingStrategy getTotal( Sale ) : Money { lowestTotal = INTEGER.MAX for each ISalePricingStrategy strat in pricingStrategies { total := strat.getTotal( sale ) lowestTotal = min( total, lowestTotal ) } return lowestTotal } CompositeBestForStore PricingStrategy getTotal( Sale ) : Money Composite Pattern (26.8) The Sale object treats a Composite Strategy that contains other strategies as any object that implements ISalePricingStrategy (i.e., calls its getTotal(s) operation) See code pp. 455-456 Notation for abstract classes and abstract methods – see Fig. 26.16 Fig. 26.16 UML notation: An abstract class is shown with an italicized name Composite PricingStrategy abstract methods are also shown with italics add( ISalePricingStrategy ) getTotal( Sale ) : Money CompositeBestForCustomer PricingStrategy getTotal( Sale ) : Money CompositeBestForStore PricingStrategy getTotal( Sale ) : Money Façade Pattern (26.9) Problem: A common unified interface to a disparate set of implementations or interfaces – such as within a subsystem – is required. There may be undesirable coupling to many things in the subsystem, or the implementation of the subsystem may change. What to do? Solution: Define a single point of contact to the subsystem – a façade that wraps the subsystem. This façade object presents a single unified interface and is responsible for collaborating with the subsystem components. Façade Pattern (26.9) A façade object serves as a “front-end” object that is the single point of entry for the services of a subsystem Façade provides Protected Variation from changes in the implementation of the subsystem Façade Pattern (26.9) Example: A “rule engine” subsystem – responsible for evaluating a set of rules against an operation and indicating if any rules invalidate the operation Example of a rule: If the sale is paid by a gift certificate, invalidate all payment types of change due back to the customer except for another gift certificate. Also known as pluggable business rules Façade Pattern (26.9) Example (cont): Define a façade object to this subsystem: POSRuleEngineFacade Calls to this façade placed near the start of methods that are points for pluggable rules, see code p. 462 The hidden subsystem could contain any number of rules Fig. 26.20 package name may be shown in the tab Domain + Sale + Register ... visibility of the package element (to outside the package) can be shown by preceding the element name with a visibility symbol POSRuleEngine + POSRuleEngineFacade * instance : RuleEngineFacade «interface» - IRule ... getInstance() : RuleEngineFacade isInvalid( SalesLineItem, Sale ) isInvalid( Payment, Sale ) ... - Rule1 ... - Rule2 ... ... Façade Pattern (26.9) Notes: – Façade is usually accessed via Singleton – Similar to Adapter but Adapter applies to varying interfaces not hiding implementation of subsystem Observer pattern • Intent: – Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically • Used in Model-View-Controller framework – Model is problem domain – View is windowing system – Controller is mouse/keyboard control • How can Observer pattern be used in other applications? • JDK’s Abstract Window Toolkit (listeners) • Java’s Thread monitors, notify(), etc. Structure of Observer Pattern Subject for all observers obs { obs->update() } +notify() +attach(in Observer) +detach(in Observer) Observer * +update() 1 ConcreteObserver ConcreteSubject -subjectSate +getState() return subjectState * +update() 1 observerState = subject->getState() Observer Pattern (26.10) Also known as Publish-Subscribe Pattern Problem: Different kinds of subscriber objects are interested in state changes or events of a publisher object and want to react in their own unique way when the publisher generates an event. The publisher wants to maintain low coupling to the subscribers. Solution: Define a subscriber or listener interface. Subscribers implement the interface. The publisher can dynamically register subscribers who are interested in an event and notify them when an event occurs. Observer Pattern (26.10) Example: Want a GUI window to refresh (update) its display of sale total when the total changes See Fig. 26.21 Fig. 26.21 Goal: When the total of the sale changes, refresh the display with the new value Sale total ... setTotal( newTotal ) ... Observer Pattern (26.10) Example (cont): Simple solution – when Sale changes its total the object sends a message to the window telling it to refresh its display Problem – high coupling between domain objects and UI objects Observer Pattern (26.10) Example (cont): Want to be able to easily replace UI objects or even add other UI objects that can be notified of this event That is, want model-view separation Model objects shouldn’t know about view objects => Protected Variations with respect to a changing user interface Fig. 26.22 { { for each PropertyListener pl in propertyListeners pl.onPropertyEvent( this, name, value ); propertyListeners.add( lis ); } } Sale addPropertyListener( PropertyListener lis ) publishPropertyEvent( name, value ) setTotal( Money newTotal ) ... { total = newTotal; publishPropertyEvent( "sale.total", total ); } javax.swing.JFrame ... setTitle() setVisible() ... propertyListeners * «interface» PropertyListener onPropertyEvent( source, name, value ) { if ( name.equals("sale.total") ) saleTextField.setText( value.toString() ); } SaleFrame1 onPropertyEvent( source, name, value ) { initialize( Sale sale ) ... } sale.addPropertyListener( this ) ... Observer Pattern (26.10) Steps (p. 465) 1. 2. 3. 4. 5. 6. Define an interface PropertyListener with operation onPropertyEvent Define window (SaleFrame1) to implement the interface When SaleFrame1 is initialized pass it the Sale instance from which it is displaying the total SaleFrame1 registers to the Sale instance for notification of “property events” via the addPropertyListener message Note that the Sale does not know about SaleFrame1 objects; it only knows about objects that implement the PropertyListener interface. (This lowers the coupling of the Sale to the window – the coupling is only to an interface, not to a GUI class.) The Sale instance is the publisher of “property events”. When the total changes, it iterates across all subscribing PropertyListeners, notifying each Observer Pattern (26.10) Notes: – The SaleFrame1 object is the observer/subscriber/listener – Sale is the publisher of property events – Sale adds SaleFrame1 object to its list of PropertyListener subscribers – Fig. 26.23 Fig. 26.23 sf : SaleFrame1 s : Sale propertyListeners : List<PropertyListener> initialize( s : Sale ) addPropertyListener( sf ) add( sf ) Observer Pattern (26.10) Notes: – When the Sale total changes it iterates over all registered subscribers and sends the onPropertyEvent message to each – Figs. 26.24, 26.25 Fig. 26.24 propertylisteners[ i ] : PropertyListener s :Sale setTotal( total ) publishPropertyEvent ( "sale.total", total ) loop onPropertyEvent( s, "sale.total", total ) Fig. 26.25 Since this is a polymorphic operation implemented by this class, show a new interaction diagram that starts with this polymorphic version : SaleFrame1 saleTextField : JTextField onPropertyEvent( source, name, value ) setText( value.toString() ) UML notation: Note this little expression within the parameter. This is legal and consise. Fig. 26.26 Sale addPropertyListener( PropertyListener lis ) publishPropertyEvent( name, value ) setTotal( Money newTotal ) ... javax.swing.JFrame propertyListeners ... setTitle() setVisible() ... publishes events to observers/listeners/ subscribers registers them when they ask to subscribe * «interface» PropertyListener onPropertyEvent( source, name, value ) SaleFrame1 listens for events observes events subscribes to notification of events onPropertyEvent( source, name, value ) initialize( Sale sale ) ... Who is the observer, listener, subscriber, and publisher? Observer Pattern (26.10) Notes: – Sale is coupled to view object but only loosely since it only knows subscribers as implementing the PropertyListener interface – In Java this was called Delegation Event Model Observer pattern is basis for GUI widget event handling in both Java (AWT & Swing) and .NET Widgets are publishers of events, other objects can register as listeners Observer Pattern (26.10) Example of AlarmClock: AlarmClock is publisher of alarm events Different types of objects can register as listeners and react to same alarm event in their own ways Fig. 26.27 { for each AlarmListener al in alarmListeners al.onAlarmEvent( this, time ); { } alarmListeners.add( lis ); } AlarmClock addAlarmnListener( AlarmListener lis ) publishAlarmEvent( time ) { setTime( newTime ) ... time = newTime; if ( time == alarmTime ) publishAlarmEvent( time ); } javax.swing.JFrame ... setTitle() setVisible() ... alarmListeners * «interface» AlarmListener onAlarmEvent( source, time ) AlarmWindow Beeper ReliabilityWatchDog onAlarmEvent( source, time ) ... onAlarmEvent( source, time ) ... onAlarmEvent( source, time ) ... { { { display notification dialog box } check that all required processes are executing normally beep } } Command pattern • Synopsis or Intent: Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations • Context: You want to model the time evolution of a program: – What needs to be done, e.g. queued requests, alarms, conditions for action – What is being done, e.g. which parts of a composite or distributed action have been completed – What has been done, e.g. a log of undoable operations • What are some applications that need to support undo? – Editor, calculator, database with transactions – Perform an execute at one time, undo at a different time • Solution: represent units of work as Command objects – Interface of a Command object can be a simple execute() method – Extra methods can support undo and redo – Commands can be persistent and globally accessible, just like normal objects Command pattern, continued • Structure: Participants (the classes and/or objects participating in this pattern): Command (Command) declares an interface for executing an operation ConcreteCommand defines a binding between a Receiver object and an action implements Execute by invoking the corresponding operation(s) on Receiver Invoker asks the command to carry out the request Receiver knows how to perform operations associated with carrying out the request Client creates a ConcreteCommand object and sets its receiver Command pattern, continued • Consequences: – You can undo/redo any Command • Each Command stores what it needs to restore state – You can store Commands in a stack or queue • Command processor pattern maintains a history – It is easy to add new Commands, because you do not have to change existing classes • Command is an abstract class, from which you derive new classes • execute(), undo() and redo() are polymorphic functions Benefits of Design Patterns • Design patterns enable large-scale reuse of software architectures and also help document systems • Patterns explicitly capture expert knowledge and design tradeoffs and make it more widely available • Patterns help improve developer communication • Pattern names form a common vocabulary
© Copyright 2024 Paperzz