Structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities.
Adapter Pattern
Adapter pattern involves a single class which is responsible to join functionalities of independent or incompatible interfaces. It allows incompatible classes to work together by converting the interface of one class into an interface expected by the clients.
A real life example could be a case of card reader which acts as an adapter between memory card and a laptop. You plugin the memory card into card reader and card reader into the laptop so that memory card can be read via laptop.
Bridge pattern is used when we need to decouple an abstraction from its implementation so that the two can vary independently. This pattern involves an interface which acts as a bridge which makes the functionality of concrete classes independent from interface implementer classes. Both types of classes can be altered structurally without affecting each other.
publicclassBridgeTest{ publicstaticvoidmain(String[] args){ ShapeDemo demo1 = new ShapeDemo(new DrawCircle()); ShapeDemo demo2 = new ShapeDemo(new DrawSquare()); demo1.draw(); demo2.draw(); } }
Composite Pattern
The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a composite is to “compose” objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.
Composite should be used when clients ignore the difference between compositions of objects and individual objects. If programmers find that they are using multiple objects in the same way, and often have nearly identical code to handle each of them, then composite is a good choice; it is less complex in this situation to treat primitives and composites as homogeneous.
//Collection of child graphics. private List<Graphic> childGraphics = new ArrayList<Graphic>();
//Prints the graphic. publicvoidprint(){ for (Graphic graphic : childGraphics) { graphic.print(); } }
//Adds the graphic to the composition. publicvoidadd(Graphic graphic){ childGraphics.add(graphic); }
//Removes the graphic from the composition. publicvoidremove(Graphic graphic){ childGraphics.remove(graphic); } }
/** "Leaf" */ classEllipseimplementsGraphic{
//Prints the graphic. publicvoidprint(){ System.out.println("Ellipse"); } }
/** Client */ publicclassProgram{
publicstaticvoidmain(String[] args){ //Initialize four ellipses Ellipse ellipse1 = new Ellipse(); Ellipse ellipse2 = new Ellipse(); Ellipse ellipse3 = new Ellipse(); Ellipse ellipse4 = new Ellipse();
//Initialize three composite graphics CompositeGraphic graphic = new CompositeGraphic(); CompositeGraphic graphic1 = new CompositeGraphic(); CompositeGraphic graphic2 = new CompositeGraphic();
//Composes the graphics graphic1.add(ellipse1); graphic1.add(ellipse2); graphic1.add(ellipse3);
graphic2.add(ellipse4);
graphic.add(graphic1); graphic.add(graphic2);
//Prints the complete graphic (four times the string "Ellipse"). graphic.print(); } }
Decorator Pattern
Decorator pattern allows a user to add new functionality to an existing object without altering its structure. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.
privatevoiddrawHorizontalScrollBar(){ // Draw the horizontal scrollbar }
@Override public String getDescription(){ returnsuper.getDescription() + ", including horizontal scrollbars"; } }
publicclassDecoratedWindowTest{ publicstaticvoidmain(String[] args){ // Create a decorated Window with horizontal and vertical scrollbars Window decoratedWindow = new HorizontalScrollBarDecorator ( new VerticalScrollBarDecorator (new SimpleWindow()));
// Print the Window's description System.out.println(decoratedWindow.getDescription()); } }
Facade Pattern
Facade pattern hides the complexities of the system and provides an interface to the client using which the client can access the system. This pattern involves a single class which provides simplified methods required by client and delegates calls to methods of existing system classes.
The Facade design pattern is often used when a system is very complex or difficult to understand because the system has a large number of interdependent classes or its source code is unavailable. This pattern hides the complexities of the larger system and provides a simpler interface to the client. It typically involves a single wrapper class which contains a set of members required by client. These members access the system on behalf of the facade client and hide the implementation details.
Flyweight pattern is primarily used to reduce the number of objects created and to decrease memory footprint and increase performance.
Flyweight pattern tries to reuse already existing similar kind objects by storing them and creates new object when no matching object is found.
We will demonstrate this pattern by drawing 20 circles of different locations but we will create only 5 objects. Only 5 colors are available so color property is used to check already existing Circle objects.
@Override publicvoiddraw(){ System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius); } }
publicclassShapeFactory{ privatestaticfinal HashMap<String, Shape> circleMap = new HashMap();
publicstatic Shape getCircle(String color){ Circle circle = (Circle)circleMap.get(color);
if(circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color : " + color); } return circle; } }
In proxy pattern, a class represents functionality of another class. We create object having original object to interface its functionality to outer world. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes.
Remote Proxy – Represents an object locally which belongs to a different address space. Think of an ATM implementation, it will hold proxy objects for bank information that exists in the remote server.
Virtual Proxy – In place of a complex or heavy object, use a skeleton representation. When an underlying image is huge in size, just represent it using a virtual proxy object and on demand load the real object. You know that the real object is expensive in terms of instantiation and so without the real need we are not going to use the real object. Until the need arises we will use the virtual proxy.
Protection Proxy – Are you working on an MNC? If so, we might be well aware of the proxy server that provides us internet by restricting access to some sort of websites like public e-mail, social networking, data storage etc. The management feels that, it is better to block some content and provide only work related web pages. Proxy server does that job. This is a type of proxy design pattern.