500 likes | 641 Vues
CS 4240: Bridge and Abstract Factory. Readings: Chap. 10 and 11. Let’s Recap Some Ideas and Strategies. We’ll assume some design-planning is useful up-front Design with change in mind Change will happen Not sure exactly what it will be
E N D
CS 4240: Bridge andAbstract Factory Readings: Chap. 10 and 11
Let’s Recap Some Ideas and Strategies • We’ll assume some design-planning is useful up-front • Design with change in mind • Change will happen • Not sure exactly what it will be • Can predict in advance where it’s likely to happen
Outline • First, factory patterns • Then, Bridge pattern
Factories • What’s a factory? • An object whose responsibilities are creating one or more objects for clients • Why bother? Why not let client create its own instances? • What do you think?
Design Goal of Factories • Sometimes we can separate knowledge of “how to use” from knowledge of “what exactly to create” • Client knows first part, factory second part • Abstract class (or interface) vs. object implements that interface • Program to abstractions • Encapsulate what varies • Factory provides objects that meet interface but client doesn’t know concrete class of that object
Reminder: Static Factory Method • Static factory method • Coding technique • Class-level method, returns an instance • Question: what design pattern relied on this • Hint: like factories, also a creational pattern (a design pattern responsible for creating objects)
Remember Singleton? • Example code: GameMaster gm = GameMaster.getInstance(); • Note here a class-level operation returns an instance • Not a separate factory object
Factory Method Pattern • Our book doesn’t mention this one, but it’s easy • GoF book intent: • Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. • Client uses reference to a factory-interface to get an object it needs
Document Processing Example • Client gets factory object • Asks factory for document • Factory provides some instance • Client doesn’t know exactly what subtype • How does factory know?
Choices and Factories • Might be one factory object that can create different types of objects • Client passes a string or some identifier • Comments on this kind of design? (Coupling?) • Often more than one kind of factory object • How does client get one? Ideas?
Choices and Factories (cont’d) • Somehow client gets a factory object • Sometimes a static method provides this DocFactory df = DocFactory.getFactory(); • Note: DocFactory will be abstract class here • How does that method know? • One option: stored in configuration file or Java property • Bottom line: some factor decides, and it’s “bound” to the client somewhere. • What makes sense? Best coupling?
Example: XML parsing • XML documents • Many parsers available, different strategies, many options for parsing • SAXParser is a standard interface • JAXP: an API but not a parser • Libraries provide parsers that work with it
Code sample • Typical use:DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();factory.setValidating(true); // factory propertiesDocumentBuilder builder = factory.newDocumentBuilder();Document doc = builder.parse(aDocFile); • How is parser set? Java properties
Abstract Factory • Intent from GoF: • Provide an interface for creating families of related or dependent objects without specifying their concrete classes • Same idea as before • Separate responsibilities of what-to-create from how-to-use • Difference: families of related objects
Possible Examples • GUIs for multiple platforms etc • Button, Label, etc. • Different implementations, but all need to be the same “family” • XML docs • Nodes, labels, children • Same operations but different parsers may produce different versions • What would make this approach work?What’s common between families?
The Abstract in Abstract Factory • In this pattern, the factory creates objects called “products” for a common family • Family could change • What doesn’t change: • Each product meets an abstract interface • E.g. Button is an abstract class, and all versions meet that • So client references products as abstractions
Same Ole Song, No? • What varies: • Family defined differences between, say, two kinds of button • So encapsulate this variation • Also, what varies is choice of family • Sometimes this, another time that • Encapsulate what-to-create inside Factory object
Textbook’s Example • Client works with a computer’s drivers. • Depending on computer, uses: • High Resolution Display Driver and High Resolution Printer Driver -- OR -- • Low Resolution Display Driver and Low Resolution Printer Driver
You Know to Do This • Application programs to interfaces • But how to make sure always using consistent objects in one family?
Use vs. Create • Client could take full responsibility for creating objects • Switch on “selection-factor” • Creating a bunch of things from one family • Now client is less cohesive • Coupling: If more families added, family details change, client must change
Abstract Factory Solution • Take what we learned from Factory Method pattern • An object is responsible for creating things for a client to use • But now: • create many different products (e.g. Button, Label, TextField, etc.) • Have one interface for creating all these • Client gets and uses an instance of the Factory object to create things
Sequence of Events • Make sure you understand the order of events • Client gets a factory of type ResFactory • Which one? How does it know? • Calls methods in this ResFactory objects to get products it needs • Uses these references to products • Abstract class or interface
Choice of Factory • Again, how does the client choose one factory? Where? • Might have a line of code to get a specific one: ResFactory factory = new LowResFact(); • Might be in a configuration file • Class-level method in ResFactory • Other possible ways (user pref, cookie,…) • But: one place to change this! • “One rule, one place”
Our Book Points Out… • Adaptors often used here to make concrete products fit AbstractProduct interface • Switches (or decisions) still here probably, just moved to one place
Summary • Division of responsibilities • How to use (client needs to know) • What to create • If abstraction used, client doesn’t need to know • Hand off responsibility to factory object • Coupling of client to family-details reduced greatly
Bridge Pattern • GoF book’s intent says: • De-couple an abstraction from its implementation so that the two can vary independently • Implementation here means: • Not the concrete class that implements an abstraction • Instead, the logic or code that makes the hard work happen • Assume this is in a helper-object
CVA yada yada yada… • What varies here? • First, we have the usual abstraction hierarchy of IS-A’s • Second, we have multiple ways work gets done (implementations) • These need to be combined • Plan: • Encapsulate what varies • Prefer aggregation to inheritance • But inheritance is in here too • Don’t use inheritance to combine across dimensions of variation
Book’s Example • Client wants to draw shapes • Has two drawing programs (engines) • Keep possibility of using either one • But shapes know which, and client doesn’t • Drawing programs may have different interfaces for drawing primitives
Book’s Example • Shapes • Rectangle, Circle, ... • Two drawing "programs" or components • We need two versions of each Shape • One uses DP1, the other DP2 • “Implementation” here means: • the drawing component used for a given Shape object
What Might Vary and Where? • Drawing programs • Different methods for primitive drawing operations • draw a line, draw a circle • Shapes • Rules for drawing a rectangle does NOT vary • four lines between corners • So this logic belongs in abstract Rectangle class
Linking in the DPs • Note four concrete classes • 2 Shapes x 2 DPs = 4 variations • The “V1 versions” must use a DP1 object • E.g. for V1Rectangle, drawLine() calls DP1’s draw-a-line method • So a DP1 object linked to V1Rectangle • See sequence chart, p. 166 • Note only 3 objects at run-time: client, someV1Rectangle, theDp1
What’s the problem(s)? • Explosion of classes • For each variation of shape, multiply that by variation in DP • Coupling • Every concrete class needs to know its family
Improvement (?) • Have an abstraction based on shape-type • Abstract class: V1Shape • Move link to particular DP up there • See next UML diagram
Better? Problem(s)? • Class explosion still here • Hard to see since 2+2 == 2x2 • But another DP? 6 concrete classes • Or another Shape? 6 concrete classes • Redundancy • Both V1Rectangle and V2Rectangle have logic of how lines are used to form a rectangle
The Overall Problem • Need to decouple two abstractions • Shape (domain object hierarchy) • Drawing program (implementation) • Both vary • Independently • Use aggregation for this coupling/link/relationship
Once again: • Aggregation separates single “thing” into two components
Comments on Bridge • Again, note what’s meant by “implementation” here • What a class needs to carry out the job • Note Rectangle and Circle are now concrete classes • Rules for how-to-draw-myself are here • One rule, one place! (See p. 179) • Note V1Drawing and V2Drawing (bad names?) are concrete classes • Quiz! What pattern is Drawing, V1Drawing, and DP1?
Comments on Bridge (2) • How does link/connect between a Shape object and a particular Drawing get made? • E.g. someRectangle uses V1Drawing object • Client must make this happen • What if clients wants lots of shapes, each using same DP? • Have we seen a pattern to help us here? • Answer:
Real Examples • Device drivers (e.g. printer drivers) • Various types of printer with variations • B&W, duplex, paper control • Various implementations for particular hardware • JDBC: Java to SQL DB driver
Summary • See book for other comments • Important point about Bridge • Decouple two abstractions that can vary simultaneously • One uses the other to implement functionality • Avoid explosion of subclasses, poor coupling, redundant code • Often used with other patternsß