Design Pattern Guide-3rd part
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 type of design pattern comes under structural pattern as this pattern adds an interface to exiting system to hide its complexities.
This pattern involves a single class which provides simplified methods which are required by client and delegates calls to existing system classes methods.
Implementation
We're going to create a Shape interface and concrete classes implementing the Shape interface. A facade class ShapeMaker is defined as a next step.
ShapeMaker class uses the concrete classes to delegates user calls to these classes.FacadePatternDemo, our demo class will use ShapeMaker class to show the results.
Step 1
Create an interface.
Shape.java
public interface Shape { void draw(); }
Step 2
Create concrete classes implementing the same interface.
Rectangle.java
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Rectangle::draw()"); } }
Square.java
public class Square implements Shape { @Override public void draw() { System.out.println("Square::draw()"); } }
Circle.java
public class Circle implements Shape { @Override public void draw() { System.out.println("Circle::draw()"); } }
Step 3
Create a facade class.
ShapeMaker.java
public class ShapeMaker { private Shape circle; private Shape rectangle; private Shape square; public ShapeMaker() { circle = new Circle(); rectangle = new Rectangle(); square = new Square(); } public void drawCircle(){ circle.draw(); } public void drawRectangle(){ rectangle.draw(); } public void drawSquare(){ square.draw(); } }
Step 4
Use the facade to draw various types of shapes.
FacadePatternDemo.java
public class FacadePatternDemo { public static void main(String[] args) { ShapeMaker shapeMaker = new ShapeMaker(); shapeMaker.drawCircle(); shapeMaker.drawRectangle(); shapeMaker.drawSquare(); } }
Step 5
Verify the output.
Circle::draw() Rectangle::draw() Square::draw()
Flyweight Pattern
Flyweight pattern is primarily used to reduce the number of objects created, to decrease memory footprint and increase performance. This type of design pattern comes under structural pattern as this pattern provides ways to decrease objects count thus improving application required objects structure.
Flyweight pattern try to reuse already existing similar kind objects by storing them and creates new object when no matching object is found. We'll demonstrate this pattern by drawing 20 circle of different locations but we'll creating only 5 objects. Only 5 colors are available so color property is used to check already existing Circle objects.
Implementation
We're going to create a Shape interface and concrete class Circle implementing the Shape interface. A factory class ShapeFactory is defined as a next step.
ShapeFactory have a HashMap of Circle having key as color of the Circle object. Whenever a request comes to create a circle of particular color to ShapeFactory. ShapeFactory checks the circle object in itsHashMap, if object of Circle found, that object is returned otherwise a new object is created, stored in hashmap for future use and returned to client.
FlyWeightPatternDemo, our demo class will use ShapeFactory to get a Shape object. It will pass information (red / green / blue/ black / white) to ShapeFactory to get the circle of desired color it needs.
Step 1
Create an interface.
Shape.java
public interface Shape { void draw(); }
Step 2
Create concrete class implementing the same interface.
Circle.java
public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color){ this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { System.out.println("Circle: Draw() [Color : " + color +", x : " + x +", y :" + y +", radius :" + radius); } }
Step 3
Create a Factory to generate object of concrete class based on given information.
ShapeFactory.java
import java.util.HashMap; public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap(); public static 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; } }
Step 4
Use the Factory to get object of concrete class by passing an information such as color.
FlyweightPatternDemo.java
public class FlyweightPatternDemo { private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" }; public static void main(String[] args) { for(int i=0; i < 20; ++i) { Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); } } private static String getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } private static int getRandomX() { return (int)(Math.random()*100 ); } private static int getRandomY() { return (int)(Math.random()*100); } }
Step 5
Verify the output.
Creating circle of color : Black Circle: Draw() [Color : Black, x : 36, y :71, radius :100 Creating circle of color : Green Circle: Draw() [Color : Green, x : 27, y :27, radius :100 Creating circle of color : White Circle: Draw() [Color : White, x : 64, y :10, radius :100 Creating circle of color : Red Circle: Draw() [Color : Red, x : 15, y :44, radius :100 Circle: Draw() [Color : Green, x : 19, y :10, radius :100 Circle: Draw() [Color : Green, x : 94, y :32, radius :100 Circle: Draw() [Color : White, x : 69, y :98, radius :100 Creating circle of color : Blue Circle: Draw() [Color : Blue, x : 13, y :4, radius :100 Circle: Draw() [Color : Green, x : 21, y :21, radius :100 Circle: Draw() [Color : Blue, x : 55, y :86, radius :100 Circle: Draw() [Color : White, x : 90, y :70, radius :100 Circle: Draw() [Color : Green, x : 78, y :3, radius :100 Circle: Draw() [Color : Green, x : 64, y :89, radius :100 Circle: Draw() [Color : Blue, x : 3, y :91, radius :100 Circle: Draw() [Color : Blue, x : 62, y :82, radius :100 Circle: Draw() [Color : Green, x : 97, y :61, radius :100 Circle: Draw() [Color : Green, x : 86, y :12, radius :100 Circle: Draw() [Color : Green, x : 38, y :93, radius :100 Circle: Draw() [Color : Red, x : 76, y :82, radius :100 Circle: Draw() [Color : Blue, x : 95, y :82, radius :100
Proxy Pattern
In Proxy pattern, a class represents functionality of another class. This type of design pattern comes under structural pattern.
In Proxy pattern, we create object having original object to interface its functionality to outer world.
Implementation
We're going to create a Image interface and concrete classes implementing the Image interface.ProxyImage is a a proxy class to reduce memory footprint of RealImage object loading.
ProxyPatternDemo, our demo class will use ProxyImage to get a Image object to load and display as it needs.
Step 1
Create an interface.
Image.java
public interface Image { void display(); }
Step 2
Create concrete classes implementing the same interface.
RealImage.java
public class RealImage implements Image { private String fileName; public RealImage(String fileName){ this.fileName = fileName; loadFromDisk(fileName); } @Override public void display() { System.out.println("Displaying " + fileName); } private void loadFromDisk(String fileName){ System.out.println("Loading " + fileName); } }
ProxyImage.java
public class ProxyImage implements Image{ private RealImage realImage; private String fileName; public ProxyImage(String fileName){ this.fileName = fileName; } @Override public void display() { if(realImage == null){ realImage = new RealImage(fileName); } realImage.display(); } }
Step 3
Use the ProxyImage to get object of RealImage class when required.
ProxyPatternDemo.java
public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_10mb.jpg"); //image will be loaded from disk image.display(); System.out.println(""); //image will not be loaded from disk image.display(); } }
Step 4
Verify the output.
Loading test_10mb.jpg Displaying test_10mb.jpg Displaying test_10mb.jpg
Chain of Responsibility Pattern
As the name suggest, the chain of responsibility pattern creates a chain of receiver objects for a request. This pattern decouples sender and receiver of a request based on type of request. This pattern comes under behavioral patterns.
In this pattern, normally each receiver contains reference to another receiver. If one object cannot handle the request then it passes the same to the next receiver and so on.
Implementation
We've created an abstract class AbstractLogger with a level of logging. Then we've created three types of loggers extending the AbstractLogger. Each logger checks the level of message to its level and print accordingly otherwise does not print and pass the message to its next logger.
Step 1
Create an abstract logger class.
AbstractLogger.java
public abstract class AbstractLogger { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; protected int level; //next element in chain or responsibility protected AbstractLogger nextLogger; public void setNextLogger(AbstractLogger nextLogger){ this.nextLogger = nextLogger; } public void logMessage(int level, String message){ if(this.level <= level){ write(message); } if(nextLogger !=null){ nextLogger.logMessage(level, message); } } abstract protected void write(String message); }
Step 2
Create concrete classes extending the logger.
ConsoleLogger.java
public class ConsoleLogger extends AbstractLogger { public ConsoleLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("Standard Console::Logger: " + message); } }
ErrorLogger.java
public class ErrorLogger extends AbstractLogger { public ErrorLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("Error Console::Logger: " + message); } }
FileLogger.java
public class FileLogger extends AbstractLogger { public FileLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("File::Logger: " + message); } }
Step 3
Create different types of loggers. Assign them error levels and set next logger in each logger. Next logger in each logger represents the part of the chain.
ChainPatternDemo.java
public class ChainPatternDemo { private static AbstractLogger getChainOfLoggers(){ AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR); AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG); AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO); errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); return errorLogger; } public static void main(String[] args) { AbstractLogger loggerChain = getChainOfLoggers(); loggerChain.logMessage(AbstractLogger.INFO, "This is an information."); loggerChain.logMessage(AbstractLogger.DEBUG, "This is an debug level information."); loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information."); } }
Step 4
Verify the output.
Standard Console::Logger: This is an information. File::Logger: This is an debug level information. Standard Console::Logger: This is an debug level information. Error Console::Logger: This is an error information. File::Logger: This is an error information. Standard Console::Logger: This is an error information.
Command Pattern
Command pattern is a data driven design pattern and falls under behavioral pattern category. A request is wrapped under a object as command and passed to invoker object. Invoker object looks for the appropriate object which can handle this command and pass the command to the corresponding object and that object executes the command.
Implementation
We've created an interface Order which is acting as a command. We've created a Stock class which acts as a request. We've concrete command classes BuyStock and SellStock implementing Orderinterface which will do actual command processing. A class Broker is created which acts as a invoker object. It can take order and place orders.
Broker object uses command pattern to identify which object will execute which command based on type of command. CommandPatternDemo, our demo class will use Broker class to demonstrate command pattern.
Step 1
Create a command interface.
Order.java
public interface Order { void execute(); }
Step 2
Create a request class.
Stock.java
public class Stock { private String name = "ABC"; private int quantity = 10; public void buy(){ System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought"); } public void sell(){ System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold"); } }
Step 3
Create concrete classes implementing the Order interface.
BuyStock.java
public class BuyStock implements Order { private Stock abcStock; public BuyStock(Stock abcStock){ this.abcStock = abcStock; } public void execute() { abcStock.buy(); } }
SellStock.java
public class SellStock implements Order { private Stock abcStock; public SellStock(Stock abcStock){ this.abcStock = abcStock; } public void execute() { abcStock.sell(); } }
Step 4
Create command invoker class.
Broker.java
import java.util.ArrayList; import java.util.List; public class Broker { private List<Order> orderList = new ArrayList<Order>(); public void takeOrder(Order order){ orderList.add(order); } public void placeOrders(){ for (Order order : orderList) { order.execute(); } orderList.clear(); } }
Step 5
Use the Broker class to take and execute commands.
CommandPatternDemo.java
public class CommandPatternDemo { public static void main(String[] args) { Stock abcStock = new Stock(); BuyStock buyStockOrder = new BuyStock(abcStock); SellStock sellStockOrder = new SellStock(abcStock); Broker broker = new Broker(); broker.takeOrder(buyStockOrder); broker.takeOrder(sellStockOrder); broker.placeOrders(); } }
Step 6
Verify the output.
Stock [ Name: ABC, Quantity: 10 ] bought Stock [ Name: ABC, Quantity: 10 ] sold
Interpreter Pattern
Interpreter pattern provides way to evaluate language grammar or expression. This type of pattern comes under behavioral patterns. This pattern involves implementing a expression interface which tells to interpret a particular context. This pattern is used in SQL parsing, symbol processing engine etc.
Implementation
We're going to create an interface Expression and concrete classes implementing the Expressioninterface. A class TerminalExpression is defined which acts as a main interpreter of context in question. Other classes OrExpression, AndExpression are used to create combinational expressions.
InterpreterPatternDemo, our demo class will use Expression class to create rules and demonstrate parsing of expressions.
Step 1
Create an expression interface.
Expression.java
public interface Expression { public boolean interpret(String context); }
Step 2
Create concrete classes implementing the above interface.
TerminalExpression.java
public class TerminalExpression implements Expression { private String data; public TerminalExpression(String data){ this.data = data; } @Override public boolean interpret(String context) { if(context.contains(data)){ return true; } return false; } }
OrExpression.java
public class OrExpression implements Expression { private Expression expr1 = null; private Expression expr2 = null; public OrExpression(Expression expr1, Expression expr2) { this.expr1 = expr1; this.expr2 = expr2; } @Override public boolean interpret(String context) { return expr1.interpret(context) || expr2.interpret(context); } }
AndExpression.java
public class AndExpression implements Expression { private Expression expr1 = null; private Expression expr2 = null; public AndExpression(Expression expr1, Expression expr2) { this.expr1 = expr1; this.expr2 = expr2; } @Override public boolean interpret(String context) { return expr1.interpret(context) && expr2.interpret(context); } }
Step 3
InterpreterPatternDemo uses Expression class to create rules and then parse them.
InterpreterPatternDemo.java
public class InterpreterPatternDemo { //Rule: Robert and John are male public static Expression getMaleExpression(){ Expression robert = new TerminalExpression("Robert"); Expression john = new TerminalExpression("John"); return new OrExpression(robert, john); } //Rule: Julie is a married women public static Expression getMarriedWomanExpression(){ Expression julie = new TerminalExpression("Julie"); Expression married = new TerminalExpression("Married"); return new AndExpression(julie, married); } public static void main(String[] args) { Expression isMale = getMaleExpression(); Expression isMarriedWoman = getMarriedWomanExpression(); System.out.println("John is male? " + isMale.interpret("John")); System.out.println("Julie is a married women? " + isMarriedWoman.interpret("Married Julie")); } }
Step 4
Verify the output.
John is male? true Julie is a married women? true
Iterator Pattern
Iterator pattern is very commonly used design pattern in Java and .Net programming environment. This pattern is used to get a way to access the elements of a collection object in sequential manner without any need to know its underlying representation.
Iterator pattern falls under behavioral pattern category.
Implementation
We're going to create a Iterator interface which narrates navigation method and a Container interface which retruns the iterator . Concrete classes implementing the Container interface will be responsible to implement Iterator interface and use it
IteratorPatternDemo, our demo class will use NamesRepository, a concrete class implementation to print a Names stored as a collection in NamesRepository.
Step 1
Create interfaces.
Iterator.java
public interface Iterator { public boolean hasNext(); public Object next(); }
Container.java
public interface Container { public Iterator getIterator(); }
Step 2
Create concrete class implementing the Container interface. This class has inner class NameIteratorimplementing the Iterator interface.
NameRepository.java
public class NameRepository implements Container { public String names[] = {"Robert" , "John" ,"Julie" , "Lora"}; @Override public Iterator getIterator() { return new NameIterator(); } private class NameIterator implements Iterator { int index; @Override public boolean hasNext() { if(index < names.length){ return true; } return false; } @Override public Object next() { if(this.hasNext()){ return names[index++]; } return null; } } }
Step 3
Use the NameRepository to get iterator and print names.
IteratorPatternDemo.java
public class IteratorPatternDemo { public static void main(String[] args) { NameRepository namesRepository = new NameRepository(); for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){ String name = (String)iter.next(); System.out.println("Name : " + name); } } }
Step 4
Verify the output.
Name : Robert Name : John Name : Julie Name : Lora
Mediator Pattern
Mediator pattern is used to reduce communication complexity between multiple objects or classes. This pattern provides a mediator class which normally handles all the communications between different classes and supports easy maintainability of the code by loose coupling. Mediator pattern falls under behavioral pattern category.
Implementation
We're demonstrating mediator pattern by example of a Chat Room where multiple users can send message to Chat Room and it is the responsibility of Chat Room to show the messages to all users. We've created two classes ChatRoom and User. User objects will use ChatRoom method to share their messages.
MediatorPatternDemo, our demo class will use User objects to show communication between them.
Step 1
Create mediator class.
ChatRoom.java
import java.util.Date; public class ChatRoom { public static void showMessage(User user, String message){ System.out.println(new Date().toString() + " [" + user.getName() +"] : " + message); } }
Step 2
Create user class
User.java
public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public User(String name){ this.name = name; } public void sendMessage(String message){ ChatRoom.showMessage(this,message); } }
Step 3
Use the User object to show communications between them.
MediatorPatternDemo.java
public class MediatorPatternDemo { public static void main(String[] args) { User robert = new User("Robert"); User john = new User("John"); robert.sendMessage("Hi! John!"); john.sendMessage("Hello! Robert!"); } }
Step 4
Verify the output.
Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John! Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!
Memento Pattern
Memento pattern is used to reduce where we want to restore state of an object to a previous state. Memento pattern falls under behavioral pattern category.
Implementation
Memento pattern uses three actor classes. Memento contains state of an object to be restored. Originator creates and stores states in Memento objects and Caretaker object which is responsible to restore object state from Memento. We've created classes Memento, Originator and CareTaker.
MementoPatternDemo, our demo class will use CareTaker and Originator objects to show restoration of object states.
Step 1
Create Memento class.
Memento.java
public class Memento { private String state; public Memento(String state){ this.state = state; } public String getState(){ return state; } }
Step 2
Create Originator class
Originator.java
public class Originator { private String state; public void setState(String state){ this.state = state; } public String getState(){ return state; } public Memento saveStateToMemento(){ return new Memento(state); } public void getStateFromMemento(Memento Memento){ state = Memento.getState(); } }
Step 3
Create CareTaker class
CareTaker.java
import java.util.ArrayList; import java.util.List; public class CareTaker { private List<Memento> mementoList = new ArrayList<Memento>(); public void add(Memento state){ mementoList.add(state); } public Memento get(int index){ return mementoList.get(index); } }
Step 4
Use CareTaker and Originator objects.
MementoPatternDemo.java
public class MementoPatternDemo { public static void main(String[] args) { Originator originator = new Originator(); CareTaker careTaker = new CareTaker(); originator.setState("State #1"); originator.setState("State #2"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #3"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #4"); System.out.println("Current State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(0)); System.out.println("First saved State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(1)); System.out.println("Second saved State: " + originator.getState()); } }
Step 5
Verify the output.
Current State: State #4 First saved State: State #2 Second saved State: State #3
No comments:
Post a Comment