Adapter pattern
It’s used so that two unrelated interfaces can work together. The object that joins these unrelated interface is called an Adapter.
interface Draw {
public void draw();
}
class Circle implements Draw {
@Override
public void draw() {
println("Drawing a circle");
}
}
interface Polygon {
public void getSides();
public void getArea();
}
class Square implements Polygon {
int length;
Square(int length){
this.length = length;
}
@Override
public void getSides() {
println("Sides: 4");
}
@Override
public void getArea() {
println("Area: "+length*length);
}
}
Client:
Draw drawingObj = null;
drawingObj = new Circle();
drawingObj.draw();
//Now lets say the client wants to draw a Square but it
//doesn't implement Draw
//drawingObj = new Square();
//drawingObj.draw() //this is not possible so we write a adapter
//in case of object adapters
drawingObj = new SquareAdapter(new Square(5));
drawingObj.draw();
((SquareAdapter) drawingObj).getSquare().getSides();
((SquareAdapter) drawingObj).getSquare().getArea();
//in case of inherited adapters
drawingObj = new SquareAdapter(5);
drawingObj.draw();
((Square) drawingObj).getSides();
((Square) drawingObj).getArea();
Object composition adapters
class SquareAdapter implements Draw { Polygon square; public SquareAdapter(Polygon square){ this.square = square; } @Override public void draw(){ println("Drawing a square"); } public Polygon getSquare() { return square; } }
Class inheritance adaptersOutput:class SquareAdapter extends Square implements Draw { SquareAdapter(int length) { super(length); } @Override public void draw(){ println("Drawing a square"); } }
[main] Drawing a circle [main] Drawing a square [main] Sides: 4 [main] Area: 25JDK: java.util.Arrays#asList() java.io.InputStreamReader(InputStream) (returns a Reader) java.io.OutputStreamWriter(OutputStream) (returns a Writer) Composite pattern is used when we have to represent a part-whole hierarchy. When we need to create a structure in a way that the objects in the structure has to be treated the same way. Client://Initialize leafs ellipses Ellipse ellipse1 = new Ellipse(); Ellipse ellipse2 = new Ellipse(); Ellipse ellipse3 = new Ellipse(); Hexagon hexagon1 = new Hexagon(); Hexagon hexagon2 = new Hexagon(); //Initialize 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(hexagon1); graphic2.add(hexagon2); graphic.add(graphic1); graphic.add(graphic2); //Prints the complete graphic (four times the string "Ellipse"). graphic.print();
JDK: Lots of Data structures like trees follow this design. java.awt.Container#add(Component) Proxy pattern Provide a surroage or placeholder for another object to control access to it Client:/** "Component" */ interface Graphic { //Prints the graphic. public void print(); } /** * "Composite" * Composite class usually contains a container for Components (list or tree or..) * Composite class usually has 3 operations * 1. add objects to the composite * 2. remove objects, iterate objects * 3. perform some operation on all or subset of the objects */ class CompositeGraphic implements Graphic { //Collection of child graphics. private List
childGraphics = new ArrayList
(); //Prints the graphic. public void print() { for (Graphic graphic : childGraphics) { if(graphic instanceof CompositeGraphic) { System.out.println("> "); graphic.print(); } else graphic.print(); } } //Adds the graphic to the composition. public void add(Graphic graphic) { childGraphics.add(graphic); } //Removes the graphic from the composition. public void remove(Graphic graphic) { childGraphics.remove(graphic); } } /** A "Leaf" Type */ class Ellipse implements Graphic { //Prints the graphic. public void print() { System.out.println("Ellipse"); } } /** Another "Leaf" Type */ class Hexagon implements Graphic { //Prints the graphic. public void print() { System.out.println("Hexagon"); } }
CommandExecutor cmdExec = new CommandExecutorImpl(); cmdExec.runCommand("rm"); //to force any client to use restricted access //do not expose CommandExecutorImpl class to the client instead expose //the proxy class CommandExecutor cmdExecProxy = new CommandExecutorProxy("supr", "asdf"); cmdExecProxy.runCommand("rm");
JDK: Java RMI Flyweight pattern Is used when we need to create a lot of Objects of a class. Since every object consumes memory space that can be crucial for low memory devices Intrinsic properties make the Object unique whereas extrinsic properties are set by client code and used to perform different operations. In below example there are no extrinsic properties. This pattern generally uses factory pattern within itself. Client:interface CommandExecutor { public void runCommand(String cmd); } class CommandExecutorImpl implements CommandExecutor { @Override public void runCommand(String cmd) { println("Running command: " + cmd); } } class CommandExecutorProxy implements CommandExecutor { private CommandExecutor executor; public CommandExecutorProxy(String user, String pwd) { // authenticate that the user has privileges // if he doesn't have then don't create the // dummy impl follows if ("super".equals(user) && pwd != null) { executor = new CommandExecutorImpl(); } } @Override public void runCommand(String cmd) { if (cmd.trim().startsWith("rm")) { // not allowed for any user using the proxy println("not allowed"); } else { executor.runCommand(cmd); } } }
Image img1 = ImageFactory.getImage(ImageType.jpeg); img1.drawImage(); Image img2 = ImageFactory.getImage(ImageType.jpeg); img2.drawImage(); Image img3 = ImageFactory.getImage(ImageType.jpeg); img3.drawImage();
JDK: wrapper classes valueOf in JDK java string pool Facade pattern Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use. Client:interface Image { public void drawImage(); } class JPEGImage implements Image { JPEGImage(){ println("creating a jpeg image"); //a sleep added to mean that it's a heavy creation process try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void drawImage() { println("drawing jpeg image"); } } class GIFImage implements Image { GIFImage(){ println("creating a gif image"); //a sleep added to mean that it's a heavy creation process try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void drawImage() { println("drawing gif image"); } } enum ImageType { jpeg, gif; } class ImageFactory { public static final Map
cache = new HashMap (); public static Image getImage(ImageType imageType) { Image image = cache.get(imageType); if (image == null) { if (imageType.equals(ImageType.jpeg)) { image = new JPEGImage(); } else if (imageType.equals(ImageType.gif)) { image = new GIFImage(); } cache.put(imageType, image); } return image; } } Shape shape = new Shape(); shape.draw("circle"); shape.draw("square"); shape.draw("square");
Decorator pattern We use inheritance or composition to extend the behavior of an object but this is done at compile time and its applicable to all the instances of the class. We can’t add any new functionality of remove any existing behavior at runtime – this is when Decorator pattern comes into picture. Client:class Circle { public void drawCircle(){ println("draws a circle"); } } class Square { public void drawSquare() { println("draws a square"); } } //both circle and square classes come from different sources //they are clossed to modification //now we create a common interface for accessing both class Shape { Circle circle; Square square; public void draw(String type) { if (type.equals("circle")) { if(circle==null) circle = new Circle(); circle.drawCircle(); } else { if(square==null) square = new Square(); square.drawSquare(); } } }
int c; try { InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt"))); while ((c = in.read()) >= 0) { System.out.print((char) c); } in.close(); } catch (IOException e) { }
class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream in) { super(in); } public int read() throws IOException { int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char) c)); } }
No comments:
Post a Comment