920 likes | 961 Views
Structural Patterns. How classes and objects are composed to form larger structures Structural class patterns : use inheritance to compose interfaces or implementations Structural object patterns: describe ways to compose objects to realize new functionality. Structural Patterns. Adapter
E N D
Structural Patterns • How classes and objects are composed to form larger structures • Structural class patterns: use inheritance to compose interfaces or implementations • Structural object patterns: describe ways to compose objects to realize new functionality
Structural Patterns • Adapter • Façade • Flyweight • Bridge • Composite • Proxy
Structural Patterns - Adapter • Intent: • Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces • Motivation: • Sometimes a toolkit or class library can not be used because its interface is incompatible with the interface required by an application • We can not change the library interface, since we may not have its source code • Even if we did have the source code, we probably should not change the library for each domain-specific application
Adapter Pattern The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces
Structural Patterns - Adapter • TextShape Example: a drawing editor that lets users draw and arrange graphical elements (lines, polygons, text, etc.) into pictures and diagrams. The drawing editor's key abstraction is the graphical object, which has an editable shape and can draw itself. The interface for graphical objects is defined by an abstract class called Shape. The editor defines a subclass of Shape for each kind of graphical object: a LineShape class for lines, a PolygonShape class for polygons, a TextShape class for text editing. • by inheriting Shape's interface and TextView's implementation • by composing a TextView instance within a TextShape and implementing TextShape in terms of TextView's interface
Structural Patterns - Adapter Class Diagram: TextShape Example
Structural Patterns - Adapter Structure: Class Diagram A class adapter uses multiple inheritance to adapt one interface to another: An object adapter relies on object composition:
Structural Patterns - Adapter • Target— defines the domain-specific interface that the client uses. • Client— collaborates with objects conforming to the Target interface. • Adaptee— defines an existing interface that needs adapting. • Adapter— adapts the interface of Adaptee to the Target interface. Participants Collaborations • Clients call operations on an Adapter instance. In turn, the Adapter calls Adaptee operations that carry out the request.
Structural Patterns - Adapter Applicability • you want to use an existing class, and its interface does not match the one you need. • you want to create a reusable class that cooperates with unrelated or unforeseen classes that don't have compatible interfaces. Implementation Issues • How much adapting should be done? • Simple interface conversion that just changes operation names and order of arguments • Totally different set of operations • Does the adapter provide two-way transparency? • A two-way adapter supports both the Target and the Adaptee interface. It allows an adapted object (Adapter) to appear as an Adaptee object or a Target object
Structural Patterns - Adapter Adapter Pattern Example 1: • The classic round pegs and square pegs! • Here's the SquarePeg class: /** * The SquarePeg class. * This is the Target class. */ public class SquarePeg { public void insert(String str) { System.out.println("SquarePeg insert(): " + str); } }
Structural Patterns - Adapter • And the RoundPeg class: /** * The RoundPeg class. * This is the Adaptee class. */ public class RoundPeg { public void insertIntoHole(String msg) { System.out.println("RoundPeginsertIntoHole(): " + msg); } } • If a client only understands the SquarePeg interface for inserting pegs using the insert() method, how can it insert round pegs? A peg adapter!
Structural Patterns - Adapter • Here is the PegAdapter class: /** * The PegAdapter class. * This is the Adapter class. * It adapts a RoundPeg to a SquarePeg. * Its interface is that of a SquarePeg. */ public class PegAdapter extends SquarePeg { private RoundPeg roundPeg; public PegAdapter(RoundPeg peg) {this.roundPeg = peg;} public void insert(String str) {roundPeg.insertIntoHole(str);} }
Structural Patterns - Adapter • Typical client program: // Test program for Pegs. public class TestPegs { public static void main(String args[]) { // Create some pegs. RoundPeg roundPeg = new RoundPeg(); SquarePeg squarePeg = new SquarePeg(); // Do an insert using the square peg. squarePeg.insert("Inserting square peg..."); // Now we'd like to do an insert using the round peg. // But this client only understands the insert() // method of pegs, not a insertIntoHole() method. // The solution: create an adapter that adapts // a square peg to a round peg! PegAdapter adapter = new PegAdapter(roundPeg); adapter.insert("Inserting round peg..."); } }
Structural Patterns - Adapter • Client program output: SquarePeg insert(): Inserting square peg... RoundPeg insertIntoHole(): Inserting round peg...
Structural Patterns - Adapter Adapter Pattern Example 2: • Notice in Example 1 that the PegAdapter adapts a RoundPeg to a SquarePeg. The interface for PegAdapter is that of a SquarePeg. • What if we want to have an adapter that acts as a SquarePeg or a RoundPeg? Such an adapter is called a two-way adapter. • One way to implement two-way adapters is to use multiple inheritance, but we can't do this in Java • But we can have our adapter class implement two different Java interfaces!
Structural Patterns - Adapter • Here are the interfaces for round and square pegs: /** *The IRoundPeg interface. */ public interface IRoundPeg { public void insertIntoHole(String msg); } /** *The ISquarePeg interface. */ public interface ISquarePeg { public void insert(String str); }
Structural Patterns - Adapter • Here are the new RoundPeg and SquarePeg classes. These are essentially the same as before except they now implement the appropriate interface. // The RoundPeg class. public class RoundPeg implements IRoundPeg { public void insertIntoHole(String msg) { System.out.println("RoundPeginsertIntoHole(): " + msg); } } // The SquarePeg class. public class SquarePeg implements ISquarePeg { public void insert(String str) { System.out.println("SquarePeg insert(): " + str); } }
Structural Patterns - Adapter • Here is the new PegAdapter class: /** * The PegAdapter class. * This is the two-way adapter class. */ public class PegAdapter implements ISquarePeg, IRoundPeg { private RoundPeg roundPeg; private SquarePeg squarePeg; public PegAdapter(RoundPeg peg) {this.roundPeg = peg;} public PegAdapter(SquarePeg peg) {this.squarePeg = peg;} public void insert(String str) {roundPeg.insertIntoHole(str);} public void insertIntoHole(String msg){squarePeg.insert(msg);} }
Structural Patterns - Adapter • A client that uses the two-way adapter: // Test program for Pegs. public class TestPegs { public static void main(String args[]) { // Create some pegs. RoundPeg roundPeg = new RoundPeg(); SquarePeg squarePeg = new SquarePeg(); // Do an insert using the square peg. squarePeg.insert("Inserting square peg..."); // Create a two-way adapter and do an insert with it. ISquarePeg roundToSquare = new PegAdapter(roundPeg); roundToSquare.insert("Inserting round peg..."); // Do an insert using the round peg. roundPeg.insertIntoHole("Inserting round peg..."); // Create a two-way adapter and do an insert with it. IRoundPeg squareToRound = new PegAdapter(squarePeg); squareToRound.insertIntoHole("Inserting square peg..."); } }
Structural Patterns - Adapter • Client program output: SquarePeg insert(): Inserting square peg... RoundPeg insertIntoHole(): Inserting round peg... RoundPeg insertIntoHole(): Inserting round peg... SquarePeg insert(): Inserting square peg...
Structural Patterns - Adapter Motivation Example 3: class Shape { public: Shape(); virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const; virtual Manipulator* CreateManipulator() const; }; class TextView { public: TextView(); void GetOrigin(Coord& x, Coord& y) const; void GetExtent(Coord& width, Coord& height) const; virtual bool IsEmpty() const; };
Structural Patterns - Adapter • Multiple Inheritance: • Key to Class Adapter: use one inheritance branch to inherit the interface and another branch to inherit the implementation class TextShape : public Shape, private TextView { public: TextShape(); virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const; virtual bool IsEmpty() const; virtual Manipulator* CreateManipulator() const; };
Structural Patterns - Adapter void TextShape::BoundingBox (Point& bottomLeft, Point& topRight) const { Coord bottom, left, width, height; GetOrigin(bottom, left); GetExtent(width, height); bottomLeft = Point(bottom, left); topRight = Point(bottom + height, left + width); } bool TextShape::IsEmpty () const { return TextView::IsEmpty(); } Manipulator* TextShape::CreateManipulator () const { return new TextManipulator(this); }
Structural Patterns - Adapter • Object adapter: use object composition to combine classes with different interfaces class TextShape : public Shape { public: TextShape(TextView*); virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const; virtual bool IsEmpty() const; virtual Manipulator* CreateManipulator() const; private: TextView* _text; };
Structural Patterns - Adapter TextShape::TextShape (TextView* t) {_text = t;} void TextShape::BoundingBox (Point& bottomLeft, Point& topRight) const { Coord bottom, left, width, height; _text->GetOrigin(bottom, left); _text->GetExtent(width, height); bottomLeft = Point(bottom, left); topRight = Point(bottom + height, left + width); } bool TextShape::IsEmpty () const { return _text->IsEmpty(); } Manipulator* TextShape::CreateManipulator () const { return new TextManipulator(this); }
Structural Patterns - Adapter • Compared with the class adapter case, the object adapter requires a little more effort to write, but it's more flexible. • the object adapter version of TextShape will work equally well with subclasses of TextView—the client simply passes an instance of a TextView subclass to the TextShape constructor
Real World Adapters • Old world Enumerators • New world Enumerators
Home Sweet Home Theater • A DVD player • A projection video system • An automated screen • Surround sound • And even • A popcorn popper
Watching a movie • Turn on the popcorn popper • Start the popper popping • Dim the lights • Put the screen down • Turn the projector on • Set the project input to DVD • Put the projector on wide-screen mode • Turn the sound amplifier on • Set the amplifier to DVD input • Set the amplifier to surround sound • Set the amplifier volumn to medium • Turn the DVD player on • Start the DVD player playing
What if: • The movie is over? • Just want to listen to CD or Radio? • Upgrade your system?
Structural Patterns - Façade Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use. Intent Applicability • Provides a simple interface to a complex subsystem. • Decouples the details of a subsystem from clients and other subsystems. • Provides a layered approach to subsystems.
Structural Patterns - Façade Class Diagram subsystem Facade
Structural Patterns - Façade Motivation
Structural Patterns - Façade • Façade • Knows which classes are responsible for each request. • Delegates client requests to appropriate objects. • Subsystem classes • Implement subsystem functionality. • Handle work assigned by the Façade object. • Have no knowledge of the façade. Participants Collaborations • Clients communicate with the subsystem sending requests to the Façade. • Reduces the number of classes the client deals with. • Simplifies the subsystem. • Clients do not have to access subsystem objects directly.
Structural Patterns - Façade Consequences Benefits • It hides the implementation of the subsystem from clients, making the subsystem easier to use • It promotes weak coupling between the subsystem and its clients. This allows you to change the classes that comprise the subsystem without affecting the clients. • It reduces compilation dependencies in large software systems • It simplifies porting systems to other platforms, because it's less likely that building one subsystem requires building all others • It does not prevent sophisticated clients from accessing the underlying classes • Note that Facade does not add any functionality, it just simplifies interfaces Liabilities • It does not prevent clients from accessing the underlying classes!
Structural Patterns - Façade An example: Compiler
Structural Patterns - Façade Façade Pattern Tutorial: https://www.youtube.com/watch?v=B1Y8fcYrz5o
Facade Pattern The Facade Pattern provides a unified interface to a set of interfaces in the subsystems. Façade defines a higher-level interface that makes the subsystem easier to use Principle of Least Knowledge—talk only to your immediate friend.
Hints • We should only invoke methods that belong to: • The object itself • Objects passed in as a parameter to the method • Any object the method creates or instantiates • Any components of the object
Bullet Points • When you need to use an existing class and its interface is not the one you need, use an adapter • When you need to simplify and unify a large interface or complex set of interfaces, use a façade • An adapter changes an interface into one a client expects
Bullet Points • A façade decouples a client from a complex subsystem. • Implementing an adapter may require little work or a great deal of work depending on the size and complexity of the target interface • Implementing a façade requires that we compose the façade with its subsystem and use delegation to perform the work of the façade
Bullet Points • There are two forms of the Adapter Pattern: object and class adapters. Class adapters require multiple inheritance • You can implement more than one façade for a subsystem • An adapter wraps an object to change its interface and a façade “wraps” a set of object to simplify.
Flyweight Benefits Reduce the number of object instances at runtime, saving memory Centralizes states for many “virtual” objects into a single location
Flyweight Uses and Drawbacks The Flyweight is used when a class has many instances, and they can all be controlled identically A drawback of the Flyweight pattern is that once you’ve implemented it, single, logical instances of the class will not be able to behave independently from the other instances.
Structural Patterns - Flyweight Flyweight Pattern Tutorial: https://www.youtube.com/watch?v=0vV-R2926ss