Jul 3, 2013

Best tutorial - Java Design patterns (Part 3) - Structural Design Patterns

Adapter Pattern

Motivation

The adapter pattern is adapting between classes and objects. Like any adapter in the real world it is used to be an interface, a bridge between two objects. In real world we have adapters for power supplies, adapters for camera memory cards, and so on. Probably everyone have seen some adapters for memory cards. If you can not plug in the camera memory in your laptop you can use and adapter. You plug the camera memory in the adapter and the adapter in to laptop slot. That's it, it's really simple.
What about software development? It's the same. Can you imagine an situation when you have some class expecting some type of object and you have an object offering the same features, but exposing a different interface? Of course, you want to use both of them so you don't to implement again one of them, and you don't want to change existing classes, so why not create an adapter...

Intent

  • Convert the interface of a class into another interface clients expect.
  • Adapter lets classes work together, that could not otherwise because of incompatible interfaces.

Implementation

The figure below shows a UML class diagram for the Adapter Pattern:
Adapter  Pattern Implementation - UML Class Diagram

The classes/objects participating in adapter pattern:
  • Target - defines the domain-specific interface that Client uses.
  • Adapter - adapts the interface Adaptee to the Target interface.
  • Adaptee - defines an existing interface that needs adapting.
  • Client - collaborates with objects conforming to the Target interface.


Applicability & Examples

The visitor pattern is used when:
  • When you have a class(Target) that invokes methods defined in an interface and you have a another class(Adapter) that doesn't implement the interface but implements the operations that should be invoked from the first class through the interface. You can change none of the existing code. The adapter will implement the interface and will be the bridge between the 2 classes.
  • When you write a class (Target) for a generic use relying on some general interfaces and you have some implemented classes, not implementing the interface, that needs to be invoked by the Target class.
Adapters are encountered everywhere. From real world adapters to software adapters
  • Non Software Examples of Adapter Patterns : Power Supply Adapters, card readers and adapters, ...
  • Software Examples of Adapter Patterns: Wrappers used to adopt 3rd parties libraries and frameworks - most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
---------

Bridge Pattern

Motivation

Sometimes an abstraction should have different implementations; consider an object that handles persistence of objects over different platforms using either relational databases or file system structures (files and folders). A simple implementation might choose to extend the object itself to implement the functionality for both file system and RDBMS. However this implementation would create a problem; Inheritance binds an implementation to the abstraction and thus it would be difficult to modify, extend, and reuse abstraction and implementation independently.

Intent

  • The intent of this pattern is to decouple abstraction from implementation so that the two can vary independently.

Implementation

The figure below shows a UML class diagram for the Bridge Pattern:
Bridge Pattern Implementation - UML Class Diagram
The participants classes in the bridge pattern are:
  • Abstraction - Abstraction defines abstraction interface.
  • AbstractionImpl - Implements the abstraction interface using a reference to an object of type Implementor.
  • Implementor - Implementor defines the interface for implementation classes. This interface does not need to correspond directly to abstraction interface and can be very different. Abstraction imp provides an implementation in terms of operations provided by Implementor interface.
  • ConcreteImplementor1, ConcreteImplementor2 - Implements the Implementor interface.

Description

An Abstraction can be implemented by an abstraction implementation, and this implementation does not depend on any concrete implementers of the Implementor interface. Extending the abstraction does not affect the Implementor. Also extending the Implementor has no effect on the Abstraction.

Applicability & Examples

The bridge pattern applies when there is a need to avoid permanent binding between an abstraction and an implementation and when the abstraction and implementation need to vary independently. Using the bridge pattern would leave the client code unchanged with no need to recompile the code.


Example - Object Persistence API Example

As discussed previously a persistence API can have many implementations depending on the presence or absence of a relational database, a file system, as well as on the underlying operating system.
Bridge Pattern Example - UML Class Diagram


------------

Composite Pattern

Motivation

There are times when a program needs to manipulate a tree data structure and it is necessary to treat both Branches as well as Leaf Nodes uniformly. Consider for example a program that manipulates a file system. A file system is a tree structure that contains Branches which are Folders as well as Leaf nodes which are Files. Note that a folder object usually contains one or more file or folder objects and thus is a complex object where a file is a simple object. Note also that since files and folders have many operations and attributes in common, such as moving and copying a file or a folder, listing file or folder attributes such as file name and size, it would be easier and more convenient to treat both file and folder objects uniformly by defining a File System Resource Interface.

Intent

  • The intent of this pattern is to compose objects into tree structures to represent part-whole hierarchies.
  • Composite lets clients treat individual objects and compositions of objects uniformly.

Implementation

The figure below shows a UML class diagram for the Composite Pattern:
Composite Pattern Implementation - UML Class Diagram

  • Component - Component is the abstraction for leafs and composites. It defines the interface that must be implemented by the objects in the composition. For example a file system resource defines move, copy, rename, and getSize methods for files and folders.
  • Leaf - Leafs are objects that have no children. They implement services described by the Component interface. For example a file object implements move, copy, rename, as well as getSize methods which are related to the Component interface.
  • Composite - A Composite stores child components in addition to implementing methods defined by the component interface. Composites implement methods defined in the Component interface by delegating to child components. In addition composites provide additional methods for adding, removing, as well as getting components.
  • Client - The client manipulates objects in the hierarchy using the component interface.
A client has a reference to a tree data structure and needs to perform operations on all nodes independent of the fact that a node might be a branch or a leaf. The client simply obtains reference to the required node using the component interface, and deals with the node using this interface; it doesn�t matter if the node is a composite or a leaf.

Applicability & Examples

The composite pattern applies when there is a part-whole hierarchy of objects and a client needs to deal with objects uniformly regardless of the fact that an object might be a leaf or a branch.

Example - Graphics Drawing Editor.

In graphics editors a shape can be basic or complex. An example of a simple shape is a line, where a complex shape is a rectangle which is made of four line objects. Since shapes have many operations in common such as rendering the shape to screen, and since shapes follow a part-whole hierarchy, composite pattern can be used to enable the program to deal with all shapes uniformly.
In the example we can see the following actors:
  • Shape (Component) - Shape is the abstraction for Lines, Rectangles (leafs) and and ComplexShapes (composites).
  • Line, Rectangle (Leafs) - objects that have no children. They implement services described by the Shape interface.
  • ComplexShape (Composite) - A Composite stores child Shapes in addition to implementing methods defined by the Shape interface.
  • GraphicsEditor (Client) - The GraphicsEditor manipulates Shapes in the hierarchy.
Alternative Implementation: Note that in the previous example there were times when we have avoided dealing with composite objects through the Shape interface and we have specifically dealt with them as composites (when using the method addToShape()). To avoid such situations and to further increase uniformity one can add methods to add, remove, as well as get child components to the Shape interface. The UML diagram below shows it:
Composite Pattern Alternative Implementation - UML Class Diagram

------------

Decorator Pattern

Motivation

Extending an object�s functionality can be done statically (at compile time) by using inheritance however it might be necessary to extend an object�s functionality dynamically (at runtime) as an object is used.
Consider the typical example of a graphical window. To extend the functionality of the graphical window for example by adding a frame to the window, would require extending the window class to create a FramedWindow class. To create a framed window it is necessary to create an object of the FramedWindow class. However it would be impossible to start with a plain window and to extend its functionality at runtime to become a framed window.

Intent

  • The intent of this pattern is to add additional responsibilities dynamically to an object.

Implementation

The figure below shows a UML class diagram for the Decorator Pattern:
Decorator Pattern Implementation - UML Class Diagram The participants classes in the decorator pattern are:
  • Component - Interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent - Defines an object to which additional responsibilities can be added.
  • Decorator - Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
  • Concrete Decorators - Concrete Decorators extend the functionality of the component by adding state or adding behavior.

Description

The decorator pattern applies when there is a need to dynamically add as well as remove responsibilities to a class, and when subclassing would be impossible due to the large number of subclasses that could result.

Applicability & Examples



Example - Extending capabilities of a Graphical Window at runtime

Decorator Pattern Example - UML Class Diagram

----------

Flyweight Pattern

Motivation

Some programs require a large number of objects that have some shared state among them. Consider for example a game of war, were there is a large number of soldier objects; a soldier object maintain the graphical representation of a soldier, soldier behavior such as motion, and firing weapons, in addition soldier�s health and location on the war terrain. Creating a large number of soldier objects is a necessity however it would incur a huge memory cost. Note that although the representation and behavior of a soldier is the same their health and location can vary greatly.

Intent

  • The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.

Implementation

The figure below shows a UML class diagram for the Flyweight Pattern:
Flyweight Pattern Implementation - UML Class Diagram
  • Flyweight - Declares an interface through which flyweights can receive and act on extrinsic state.
  • ConcreteFlyweight - Implements the Flyweight interface and stores intrinsic state. A ConcreteFlyweight object must be sharable. The Concrete flyweight object must maintain state that it is intrinsic to it, and must be able to manipulate state that is extrinsic. In the war game example graphical representation is an intrinsic state, where location and health states are extrinsic. Soldier moves, the motion behavior manipulates the external state (location) to create a new location.
  • FlyweightFactory - The factory creates and manages flyweight objects. In addition the factory ensures sharing of the flyweight objects. The factory maintains a pool of different flyweight objects and returns an object from the pool if it is already created, adds one to the pool and returns it in case it is new.
    In the war example a Soldier Flyweight factory can create two types of flyweights : a Soldier flyweight, as well as a Colonel Flyweight. When the Client asks the Factory for a soldier, the factory checks to see if there is a soldier in the pool, if there is, it is returned to the client, if there is no soldier in pool, a soldier is created, added to pool, and returned to the client, the next time a client asks for a soldier, the soldier created previously is returned, no new soldier is created.
  • Client - A client maintains references to flyweights in addition to computing and maintaining extrinsic state
A client needs a flyweight object; it calls the factory to get the flyweight object. The factory checks a pool of flyweights to determine if a flyweight object of the requested type is in the pool, if there is, the reference to that object is returned. If there is no object of the required type, the factory creates a flyweight of the requested type, adds it to the pool, and returns a reference to the flyweight. The flyweight maintains intrinsic state (state that is shared among the large number of objects that we have created the flyweight for) and provides methods to manipulate external state (State that vary from object to object and is not common among the objects we have created the flyweight for).

Applicability & Examples

The flyweight pattern applies to a program using a huge number of objects that have part of their internal state in common where the other part of state can vary. The pattern is used when the larger part of the object�s state can be made extrinsic (external to that object).


Example - The war game.

The war game instantiates 5 Soldier clients, each client maintains its internal state which is extrinsic to the soldier flyweight. And Although 5 clients have been instantiated only one flyweight Soldier has been used.
Flyweight Pattern Example - UML Class Diagram 
----------

Memento Pattern

Motivation

It is sometimes necessary to capture the internal state of an object at some point and have the ability to restore the object to that state later in time. Such a case is useful in case of error or failure. Consider the case of a calculator object with an undo operation such a calculator could simply maintain a list of all previous operation that it has performed and thus would be able to restore a previous calculation it has performed. This would cause the calculator object to become larger, more complex, and heavyweight, as the calculator object would have to provide additional undo functionality and should maintain a list of all previous operations. This functionality can be moved out of the calculator class, so that an external (let's call it undo manager class) can collect the internal state of the calculator and save it. However providing the explicit access to every state variable of the calculator to the restore manager would be impractical and would violate the encapsulation principle.

Intent

  • The intent of this pattern is to capture the internal state of an object without violating encapsulation and thus providing a mean for restoring the object into initial state when needed.

Implementation

The figure below shows a UML class diagram for the Memento Pattern:
Memento Pattern Implementation - UML Class Diagram
  • Memento
    • Stores internal state of the Originator object. The state can include any number of state variables.
    • The Memento must have two interfaces, an interface to the caretaker. This interface must not allow any operations or any access to internal state stored by the memento and thus honors encapsulation. The other interface is to the originator and allows the originator to access any state variables necessary to for the originator to restore previous state.
  • Originator
    • Creates a memento object capturing the originators internal state.
    • Use the memento object to restore its previous state.
  • Caretaker
    • Responsible for keeping the memento.
    • The memento is opaque to the caretaker, and the caretaker must not operate on it.
A Caretaker would like to perform an operation on the Originator while having the possibility to rollback. The caretaker calls the createMemento() method on the originator asking the originator to pass it a memento object. At this point the originator creates a memento object saving its internal state and passes the memento to the caretaker. The caretaker maintains the memento object and performs the operation. In case of the need to undo the operation, the caretaker calls the setMemento() method on the originator passing the maintained memento object. The originator would accept the memento, using it to restore its previous state.

Applicability & Examples

The memento pattern is used when a snapshot of an object's state must be captured so that it can be restored to that state later and in situations where explicitly passing the state of the object would violate encapsulation.

Example - Simple Calculator with Undo Operation.

This simple example is a calculator that finds the result of addition of two numbers, with the additional option to undo last operation and restore previous result.
Memento Pattern Alternative Implementation - UML Class Diagram

-------

Proxy Pattern

Motivation

Sometimes we need the ability to control the access to an object. For example if we need to use only a few methods of some costly objects we'll initialize those objects when we need them entirely. Until that point we can use some light objects exposing the same interface as the heavy objects. These light objects are called proxies and they will instantiate those heavy objects when they are really need and by then we'll use some light objects instead.
This ability to control the access to an object can be required for a variety of reasons: controlling when a costly object needs to be instantiated and initialized, giving different access rights to an object, as well as providing a sophisticated means of accessing and referencing objects running in other processes, on other machines.
Consider for example an image viewer program. An image viewer program must be able to list and display high resolution photo objects that are in a folder, but how often do someone open a folder and view all the images inside. Sometimes you will be looking for a particular photo, sometimes you will only want to see an image name. The image viewer must be able to list all photo objects, but the photo objects must not be loaded into memory until they are required to be rendered.

Intent

  • The intent of this pattern is to provide a �Placeholder� for an object to control references to it.

Implementation

The figure below shows a UML class diagram for the Proxy Pattern:
Proxy Pattern Implementation - UML Class Diagram
The participants classes in the proxy pattern are:
  • Subject - Interface implemented by the RealSubject and representing its services. The interface must be implemented by the proxy as well so that the proxy can be used in any location where the RealSubject can be used.
  • Proxy
    • Maintains a reference that allows the Proxy to access the RealSubject.
    • Implements the same interface implemented by the RealSubject so that the Proxy can be substituted for the RealSubject.
    • Controls access to the RealSubject and may be responsible for its creation and deletion.
    • Other responsibilities depend on the kind of proxy.
  • RealSubject - the real object that the proxy represents.

Description

A client obtains a reference to a Proxy, the client then handles the proxy in the same way it handles RealSubject and thus invoking the method doSomething(). At that point the proxy can do different things prior to invoking RealSubject�s doSomething() method. The client might create a RealSubject object at that point, perform initialization, check permissions of the client to invoke the method, and then invoke the method on the object. The client can also do additional tasks after invoking the doSomething() method, such as incrementing the number of references to the object.

Applicability & Examples

The Proxy design pattern is applicable when there is a need to control access to an Object, as well as when there is a need for a sophisticated reference to an Object. Common Situations where the proxy pattern is applicable are:
  • Virtual Proxies: delaying the creation and initialization of expensive objects until needed, where the objects are created on demand (For example creating the RealSubject object only when the doSomething method is invoked).
  • Remote Proxies: providing a local representation for an object that is in a different address space. A common example is Java RMI stub objects. The stub object acts as a proxy where invoking methods on the stub would cause the stub to communicate and invoke methods on a remote object (called skeleton) found on a different machine.
  • Protection Proxies: where a proxy controls access to RealSubject methods, by giving access to some objects while denying access to others.
  • Smart References: providing a sophisticated access to certain objects such as tracking the number of references to an object and denying access if a certain number is reached, as well as loading an object from database into memory on demand.


Example - Virtual Proxy Example.

Consider an image viewer program that lists and displays high resolution photos. The program has to show a list of all photos however it does not need to display the actual photo until the user selects an image item from a list.
Proxy Pattern Virtual Proxy Example - UML Class Diagram

The code below shows the Image interface representing the Subject. The interface has a single method showImage() that the Concrete Images must implement to render an image to screen.
package proxy;

/**
 * Subject Interface
 */
public interface Image {

 public void showImage();
 
}

The code below shows the Proxy implementation, the image proxy is a virtual proxy that creates and loads the actual image object on demand, thus saving the cost of loading an image into memory until it needs to be rendered:
package proxy;

/**
 * Proxy
 */
public class ImageProxy implements Image {

 /**
  * Private Proxy data 
  */
 private String imageFilePath;
 
 /**
  * Reference to RealSubject
  */
 private Image proxifiedImage;
 
 
 public ImageProxy(String imageFilePath) {
  this.imageFilePath= imageFilePath; 
 }
 
 @Override
 public void showImage() {

  // create the Image Object only when the image is required to be shown
  
  proxifiedImage = new HighResolutionImage(imageFilePath);
  
  // now call showImage on realSubject
  proxifiedImage.showImage();
  
 }

}

The code below displays the RealSubject Implementation, which is the concrete and heavyweight implementation of the image interface. The High resolution image, loads a high resolution image from disk, and renders it to screen when showImage() is called.
package proxy;

/**
 * RealSubject
 */
public class HighResolutionImage implements Image {

 public HighResolutionImage(String imageFilePath) {
  
  loadImage(imageFilePath);
 }

 private void loadImage(String imageFilePath) {

  // load Image from disk into memory
  // this is heavy and costly operation
 }

 @Override
 public void showImage() {

  // Actual Image rendering logic

 }

}

The code below illustrates a sample image viewer program; the program simply loads three images, and renders only one image, once using the proxy pattern, and another time directly. Note that when using the proxy pattern, although three images have been loaded, the High resolution image is not loaded into memory until it needs to be rendered, while in the part not using the proxy, the three images are loaded into memory although one of them is actually rendered.
package proxy;

/**
 * Image Viewer program
 */
public class ImageViewer {

 
 public static void main(String[] args) {
  
 // assuming that the user selects a folder that has 3 images 
 //create the 3 images  
 Image highResolutionImage1 = new ImageProxy("sample/veryHighResPhoto1.jpeg");
 Image highResolutionImage2 = new ImageProxy("sample/veryHighResPhoto2.jpeg");
 Image highResolutionImage3 = new ImageProxy("sample/veryHighResPhoto3.jpeg");
 
 // assume that the user clicks on Image one item in a list
 // this would cause the program to call showImage() for that image only
 // note that in this case only image one was loaded into memory
 highResolutionImage1.showImage();
 
 // consider using the high resolution image object directly
 Image highResolutionImageNoProxy1 = new HighResolutionImage("sample/veryHighResPhoto1.jpeg");
 Image highResolutionImageNoProxy2 = new HighResolutionImage("sample/veryHighResPhoto2.jpeg");
 Image highResolutionImageBoProxy3 = new HighResolutionImage("sample/veryHighResPhoto3.jpeg");
 
 
 // assume that the user selects image two item from images list
 highResolutionImageNoProxy2.showImage();
 
 // note that in this case all images have been loaded into memory 
 // and not all have been actually displayed
 // this is a waste of memory resources
 
 }
  
}


(Source: Internet)

1 comment: