Mechanisms for improving software reuse Design Patterns Mechanisms for improving software reuse
Copyright 2000, Georgia Tech Story What are Design Patterns? An example pattern Why do we care about them? Example Design Patterns Creational Structural Behavioral Design Patterns in Smalltalk 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech References Design Patterns: Elements of Reusable Object-Oriented Software “Gang of Four”: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (Addison-Wesley, 1995) Best-selling Computer Science book ever The Design Patterns Smalltalk Companion Sherman R. Alpert, Kyle Brown, Bobby Woolf (Addison-Wesley, 1998) 1/1/2019 Copyright 2000, Georgia Tech
What are Design Patterns? Codified standard practices of expert designers “Recorded experience in designing object-oriented software” – Gang of Four “A reusable implementation model or architecture that can be applied to solve a particular recurring class of problem” — Alpert et al. Definitely not innovative, unique approaches Instead, tried-and-true, worth reusing practices Practices that address common design problems Practices that help improve reusability 1/1/2019 Copyright 2000, Georgia Tech
Pieces of a Design Pattern Pattern Name Problem: When to apply the pattern Solution: The elements that make up the design, their relationships, responsibilities, collaborators. Not a concrete design or implementation, but a template Consequences: Results and tradeoffs of the pattern 1/1/2019 Copyright 2000, Georgia Tech
Your first pattern: Observer “Intent: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.” – G4 Participants: (Abstract) Subjects: Know observers and can attach/detach them (Abstract) Observers: Can update() when notified of changes ConcreteSubjects maintain state for subject ConcreteObservers maintain a relationship with the ConcreteSubject 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Observer Structure * 1 1/1/2019 Copyright 2000, Georgia Tech
An instantiation of Observer: MVC! You’ve seen this before! All the issues are the same! Subjects are Models Your application specific Models are ConcreteSubjects User Interface Components (Views) are Observers The specific UI components you use in your application are ConcreteObservers Observer is also the pattern being used in Java’s Listener class in Swing 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Using Observer Use the observer pattern when… A change to one object requires updating many When an object should be able to notify other objects without making assumptions about who those objects are (loosely coupled) When an abstraction has two aspects, one dependent on the other, but you want to vary and reuse them independently Note: These are not just about UI! 1/1/2019 Copyright 2000, Georgia Tech
Consequences of Observer Abstract coupling between Subject and Observer Could be an issue in large, multi-layered system Requires support for broadcast communication Freedom to add/remove observers anytime Can be computationally expensive Unexpected updates Observer and subjects are blind to the costs of sending each other messages 1/1/2019 Copyright 2000, Georgia Tech
Implementation Issues How track observers? Observing more than one subject is complex Who triggers the update? Beware that subject state is updated before notifying Avoid observer-specific update protocols: Push vs. Pull Specifying aspects of interest explicitly Encapsulating complex update semantics 1/1/2019 Copyright 2000, Georgia Tech
Patterns in Architecture “Each 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” — Christopher Alexander Alexander is an Architect who has been collecting patterns in Architecture for years Standard ways of solving problems 1/1/2019 Copyright 2000, Georgia Tech
Patterns in Cognitive Science Experts do think in pattern-like elements Sometimes called “chunks” or “plans” Shown by Herb Simon for Chess Shown by Elliot Soloway for Software Can we teach these patterns to people to make them better designers? 1/1/2019 Copyright 2000, Georgia Tech
Describing Design Patterns Name and classification Intent Also Known As (AKA) Motivation Applicability Structure Participants Collaborations Consequences Implementation issues Sample code Known uses Related Patterns 1/1/2019 Copyright 2000, Georgia Tech
Classifications of Design Patterns Creational Make a system independent of how its objects are created, composed, and represented Structural How classes and objects are composed to form larger structures Behavioral The patterns of communication between objects 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Patterns for Reuse Patterns build heavily on composition and delegation Inheritance is a “white box” form of reuse Its faster and straightforward But requires a lot of knowledge of superclass Composition and delegation is “black box” reuse Keeps details hidden away In general, program to an interface, not an implementation 1/1/2019 Copyright 2000, Georgia Tech
Design Patterns Solve Common Reuse Problems Example 1: Creating an object by specifying a class explicitly If you specify a class name when you create an object, you’re committing to a particular implementation (that class) as opposed to a particular interface (e.g., features that you need) To avoid it, create objects indirectly Solutions are Creational patterns 1/1/2019 Copyright 2000, Georgia Tech
Solution to #1: Factory Method Pattern Intent: Define an interface for creating an object, but let subclasses decide which class to instantiate Have a factory method (perhaps, take a parameter that tells you the kind of object you want) decide which object to give you Example: Application suite that can create Word Processing, Spreadsheet, Draw documents 1/1/2019 Copyright 2000, Georgia Tech
Factory Method Applicability Use it when… A class can’t anticipate the class of objects it must create A class wants its subclasses to specify the objects it creates You want to localize the knowledge of which specific class gets created for a specific purpose 1/1/2019 Copyright 2000, Georgia Tech
Factory Method Participants Product: Defines the interface of objects that the factory method creates (e.g., all documents can open, close, save, etc.) ConcreteProduct: Implements the Product interface (e.g., a WP document) Creator: Defines the Factory Method ConcreteCreator: Overrides the Factory Method to create an instance of ConcreteProduct 1/1/2019 Copyright 2000, Georgia Tech
Factory Method Structure 1/1/2019 Copyright 2000, Georgia Tech
Consequences of Factory Method Disadvantage: You have to have a ConcreteCreator class for every product you create You need to provide hooks for subclasses Connects parallel class hierarchies Makes class evolution and development a little more complex 1/1/2019 Copyright 2000, Georgia Tech
Implementing Factory Method in Smalltalk Imagine a CarBuilder abstract class, with subclasses FordBuilder and ToyotaBuilder Each wants to build 4 cylinder cars addFourCylinderEngine “in CarBuilder” self car addEngine: self fourCylinderEngine fourCylinderEngine “in FordBuilder” ^Ford4CylinderEngine new fourCylinderEngine “in ToyotaBuilder” ^Toyota4CylinderEngine new 1/1/2019 Copyright 2000, Georgia Tech
Alternative Factory Method Implementation in Smalltalk Return the class itself! addFourCylinderEngine “in CarBuilder” self car addEngine: self fourCylinderEngine fourCylinderEngine “in CarBuilder” ^self myFourCylinderEngineClass new myFourCylinderEngineClass “in FordBuilder” ^Ford4CylinderEngine myFourCylinderEngineClass “in ToyotaBuilder” ^Toyota4CylinderEngine You can return a class by just using the name of the class. Another way to get the class is to use Smalltalk at: #ClassName. 1/1/2019 Copyright 2000, Georgia Tech
Related Pattern: Abstract Factory Intent: Provide an interface for creating families of related or dependent objects. In some sense, select a class which has the Factory Methods you need 1/1/2019 Copyright 2000, Georgia Tech
Abstract Factory Example 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Abstract Factory Code myFactory := self factory. “FordFactory or ToyotaFactory returned.” myEngine := myFactory makeEngine. myBody := myFactory makeBody. 1/1/2019 Copyright 2000, Georgia Tech
Problem #2: Hardware/software dependence Redesign/reuse problem #2: Hardware/software dependence You want to limit your dependency on software specifics or hardware specifics Can solve this with an Abstract Factory Can also solve this with the Behavioral Pattern, Bridge 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Bridge Pattern Intent: Decouple an abstraction from its implementation so that the two can vary independently Basically, separate the interface and implementation so that the two can vary independently Classic example: All windowing systems offer similar functionality, but vary in implementation/interface 1/1/2019 Copyright 2000, Georgia Tech
Bridge Pattern Example 1/1/2019 Copyright 2000, Georgia Tech
Interesting Uses for Bridges Not just to hide platform dependencies! IBM Smalltalk separated collections into implementations and interfaces If a Set was small, stored in a LinearSetImplementation If a Set was large, stored in a LinearHashSetImplementation Programmer-User only saw the same Set interface—the implementation changed invisibly 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech When to Bridge You want to avoid a permanent binding between an abstraction and its implementation Both abstraction and implementation might be extensible via subclassing Changes in implementation should not impact clients of the abstraction 1/1/2019 Copyright 2000, Georgia Tech
Bridge Implementation Issues What if only one implementor? Still might be useful In Java/C++, can avoid changing client, just re-link Choosing the right implementation object May have to change later, depending on size, platform, etc. Can use a factory to choose implementation for us! 1/1/2019 Copyright 2000, Georgia Tech
Problem #3: Dependence on Specific Operations Reuse/Redesign Problem #3: When you specify a particular operation, you are committing to one way of satisfying a request. If you can remain flexible with how you respond to requests, you make it easier to change, even (in C++/Java/etc.) at run-time or compile-time One solution design pattern: Command 1/1/2019 Copyright 2000, Georgia Tech
Command—A Behavioral Design Pattern Intent: Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. AKA: Action, or Transaction pattern Sometimes, you want to ask an object to do something without knowing the actual message name or even the receiver of the message. Do this by making the request itself be an object 1/1/2019 Copyright 2000, Georgia Tech
Motivation for Command An Application wants to have a Menu that sends commands to Documents like Open, Close, Paste, Copy The MenuItem doesn’t necessarily know which document gets the command The MenuItem may not even know which message the document understands Further, the creation of an inverse (for Undo) is not the Menu’s responsibility 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Command Structure 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Command Participants Command: Declares the interface for an operation ConcreteCommand: Binds a Receiver and an action Implements Execute() Client: Creates ConcreteCommand, sets its receiver Invoker: Asks command to carry out request Receiver: Knows how to do the operation 1/1/2019 Copyright 2000, Georgia Tech
Use Command when you want to... Parameterize objects by an action to perform (e.g., menuItem and pushButton both do same Command object) Specify, queue, and execute requests at different times Support undo or redo (put Commands in a stack or queue) Support logging changes Structure a system around high-level operations built on primitive operations 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Command Consequences Command decouples the object invoking operation from one that performs it Commands are first-class objects that can be subclassed, etc. Commands can be assembled into macros It’s easy to add new Commands—you don’t actually have to change existing classes 1/1/2019 Copyright 2000, Georgia Tech
Smalltalk Pluggable Command Create a class PluggableCommand with instance variables receiver, selector, and arguments command := PluggableCommand receiver: self selector: #cut arguments: (Array with: myTextPane) 1/1/2019 Copyright 2000, Georgia Tech
PluggableCommand execute execute “PluggableCommand” ^self receiver perform: self selector withArguments: self arguments 1/1/2019 Copyright 2000, Georgia Tech
Design Problem #4: Adapter Design problem #4: Inability to alter classes conveniently Sometimes you have to change something (e.g., you need an interface to be like this, but it’s implemented like that), but you can’t easily — it’s a system that you don’t have source to, or it’s in another language, or it’s big and complicated Solution: Structural pattern adapter 1/1/2019 Copyright 2000, Georgia Tech
Structural pattern Adapter Intent: Convert the interface of a class into another interface clients expect. Basically, put a “wrapper” around something, so that it looks right Pluggable components do this! Essentially, they let a standard interface work for any UI component 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Adapter Structure 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Adapter Participants Target: Defines the domain-specific interface for the Client Client: Collaborates with objects using the Target interface Adaptee: Defines the existing interface Adapter: Makes the adaptee more usable by implementing the Target interface and using it to adapt the adaptee 1/1/2019 Copyright 2000, Georgia Tech
Copyright 2000, Georgia Tech Adapter Consequences Adapter adapts for all subclasses of adaptee, too Adapter makes it harder to override adaptee behavior—have to make adapter talk to adaptee subclass 1/1/2019 Copyright 2000, Georgia Tech
Parameterized Adapters in Smalltalk Define a class ParameterizedAdapter with instance variables adaptee, getBlock, and setBlock. adapter := ParameterizedAdapter on: someObject. Adapter getBlock: [:x | “something that gets a value for someObject”]; setBlock: [:x | “Something that sets a value for someObject”]. 1/1/2019 Copyright 2000, Georgia Tech
Arguments Against Patterns Maybe these are things that should just be language features? Alexander’s approach has not been accepted in Architecture His efforts in defining patterns have only described a few small classes of buildings (e.g., cottages) Real experts have lots of chunks Simon estimates 10,000 of them John Anderson says that you can’t teach them directly, only through experience 1/1/2019 Copyright 2000, Georgia Tech