CS 4240: Bridge and Abstract Factory Readings: Chap. 10 and 11 Let’s Recap Some Ideas and Strategies We’ll assume some designplanning 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 factoryinterface 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 properties DocumentBuilder 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” General Form 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 UML for Shape Hierarchy 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 More Details Two Abstractions in the Bridge 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 AWT Windows 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ß END