Showing posts with label structural. Show all posts
Showing posts with label structural. Show all posts

Sunday, August 31, 2014

Structural design patterns in Java

Simple examples of using structural design patterns in Java.
List of them from wikipedia:
Examples of Structural Patterns include:
  • Adapter pattern: 'adapts' one interface for a class into one that a client expects
    • Adapter pipeline: Use multiple adapters for debugging purposes.[1]
    • Retrofit Interface Pattern:[2][3] An adapter used as a new interface for multiple classes at the same time.
  • Bridge pattern: decouple an abstraction from its implementation so that the two can vary independently
    • Tombstone: An intermediate "lookup" object contains the real location of an object.[4]
  • Composite pattern: a tree structure of objects where every object has the same interface
  • Decorator pattern: add additional functionality to a class at runtime where subclassing would result in an exponential rise of new classes
  • Facade pattern: create a simplified interface of an existing interface to ease usage for common tasks
  • Flyweight pattern: a high quantity of objects share a common properties object to save space
  • Proxy pattern: a class functioning as an interface to another thing

1. Adapter pattern.

 Actors:
  1. "convenient" interface
  2. adapter class which adapt "non-convenient" classes to match "convenient" interface
  Goal: using methods of interface on class which doesn't implements that interface using adaptor class.

Main class:

public class Adaptor {
    
    public interface Movable {
        String move();
    }
    
    public class Shape {
        private String name;
        
        public Shape(String name) {
            this.name=name;
        }
        
        public String relocate() {
            return "shape "+name+" is relocated";
        }
    }
    
    public class ShapeToMovableAdaptor implements Movable {
        
        private Shape shape;
        
        public ShapeToMovableAdaptor(Shape shape) {
            this.shape=shape;
        }

        @Override
        public String move() {          
            return shape.relocate();
        }   
    }
}



Test class:

public class AdaptorTest {
    
    @Test
    public void test() {
        Adaptor adaptor=new Adaptor();
        
        Adaptor.Shape shape=adaptor. new Shape("circle");
        
        Adaptor.Movable shapeAdaptor=adaptor. new ShapeToMovableAdaptor(shape);
        
        String result=shapeAdaptor.move();
        
        Assert.assertEquals("shape circle is relocated", result);
    }

}


2. Bridge

  Actors:
    1. Implementation
    2. Abstraction - which depends(aggregate) on Implementation (for instance, Implementation set in constructor)
    3. Concrete classes which extends Abstraction
  Goal: implementation separated from abstraction
Main class:


public class Bridge {
    
    interface Implementation {
        String move();
    }
    
    class FastImplementation implements Implementation {
        @Override
        public String move() {
            return "fast";
        }       
    }
    
    class SlowImplementation implements Implementation {
        @Override
        public String move() {
            return "slow";
        }       
    }   
    
    
    public abstract class Abstraction{
        
        Implementation implementation;
        
        public Abstraction(Implementation implementation) {
            this.implementation=implementation;
        }
        
        public String rellocate() {
            return implementation.move() +" rellocation";
        }
        
    }
    
    public class ConcreteSlowClass extends Abstraction {

        public ConcreteSlowClass() {
            super(new SlowImplementation());
        }
        
    }
    
    public class ConcreteFastClass extends Abstraction {

        public ConcreteFastClass() {
            super(new FastImplementation());
        }
        
    }   
}

Test class:

public class BridgeTest {

    @Test
    public void test() {
        Bridge bridge=new Bridge();
        
        Bridge.ConcreteFastClass fast=bridge. new ConcreteFastClass();
        assertEquals("fast rellocation", fast.rellocate());
        
        
        Bridge.ConcreteSlowClass slow=bridge. new ConcreteSlowClass();
        assertEquals("slow rellocation", slow.rellocate());
    }

}

3. Composite

Actors:
  1. interface
  2. simple object which implements interface
  3. complex object(contain set of simple objects) with implements interface
  Goal:
  Do some logic with set(array) of objects like one single object
Main class:


public class Composite {

    public interface drawable {
        String draw();
    }

    public class SimpleObject implements drawable {

        String name;

        @Override
        public String draw() {
            return "drawing " + name;
        }

        public SimpleObject(String name) {
            this.name = name;
        }

    }

    public class CompositeObject implements drawable {

        List<Composite.SimpleObject> objects=new ArrayList<Composite.SimpleObject>();

        public void addObject(Composite.SimpleObject object) {
            objects.add(object);
        }

        @Override
        public String draw() {
            StringBuilder result = new StringBuilder();

            for (Composite.SimpleObject object : objects) {
                result.append(object.draw() + ".");
            }

            return result.toString();
        }

Test class:

    }

}
public class CompositeTest {

    @Test
    public void test() {
        Composite composite=new Composite();
        
        Composite.SimpleObject simple1=composite. new SimpleObject("first");
        assertEquals("drawing first", simple1.draw());
        
        Composite.SimpleObject simple2=composite. new SimpleObject("second");
        
        Composite.CompositeObject complex=composite. new CompositeObject();
        complex.addObject(simple1);
        complex.addObject(simple2);
                
        assertEquals("drawing first.drawing second.", complex.draw());
                
    }

}

4. Decorator

  Actors:
  1. original class
  2. decorator class which wrap original class
  Goal: extend functionality of original class
Main class:


public class Decorator {
    
    public static class Shape {
        public String draw() {
            return "shape";
        }
    }
    
    public static class RedDecorator  {
        private Shape shape;

        public RedDecorator(Shape shape) {
            this.shape=shape;
        }

        public String drawRed() {
            return shape.draw()+" is red";
            
        }       
    }
    
    public static class BigDecorator {
        private RedDecorator redDecorator;

        public BigDecorator(RedDecorator redDecorator) {
            this.redDecorator=redDecorator;
        }

        public String drawBig() {
            return redDecorator.drawRed()+" and big";
            
        }       
    }   

}

Test class:

public class DecoratorTest {

    @Test
    public void test() {

        String result=new Decorator.BigDecorator(new Decorator.RedDecorator(new Decorator.Shape())).drawBig();


        assertEquals("shape is red and big", result);
        
    }

}

5. Facade

Actors:
  1. set of classes  (library)
  2. facade class for managing them
  Goal: interface for library: one class which manage other classes

Main class:

public class Facade {
    
    public interface Drawable {
        public String draw();
    }
    
    public class Square implements Drawable {

        @Override
        public String draw() {          
            return "square.";
        }
        
    }
    
    public class Circle implements Drawable {

        @Override
        public String draw() {          
            return "circle.";
        }
        
    }
    
    
    public class ComplexDrawingFacade {
                
        public String drawComplexObject() {
            Square square1=new Square();
            Square square2=new Square();
            Circle circle=new Circle();
            
            String result=square1.draw()+circle.draw()+square2.draw();
            
            return result;      
        }
        
    }

}

Test class:

public class FacadeTest {

    @Test
    public void test() {
        Facade facade=new Facade();
        
        Facade.ComplexDrawingFacade compleDrawingFacade=facade. new ComplexDrawingFacade();
        assertEquals("square.circle.square.", compleDrawingFacade.drawComplexObject());
    }

}

6. FlyWeight

Actors:
 1. set of objects
 2. flyweight(cache) object: contains list of created objects
 Goal: using object cache(for memory minimizing) and object sharing instead of new object creation


public class FlyWeight {
    
    public static abstract class AbstractShape {
        public abstract String draw();
    }
    
    public static class Shape extends AbstractShape {

        @Override
        public String draw() {
            return "shape";
        }       
    }
    
    public static class Circle extends AbstractShape {

        @Override
        public String draw() {
            return "circle";
        }       
    }
    
    public class FlyWeightFactory {
        HashMap<String, AbstractShape> cache=new HashMap<String, AbstractShape>(); 
        public AbstractShape lookUp(Class<?> cl) throws InstantiationException, IllegalAccessException {
            String className=cl.getCanonicalName();
            if (!cache.containsKey(className)) {
                try {
                    Object o=cl.newInstance();
                } catch(Exception e) {
                    e.printStackTrace();
                }
                AbstractShape shape=(AbstractShape)cl.newInstance();
                
                cache.put(className, shape);
            }           
            return cache.get(className);
        }
    }

}

Test class:

public class FlyWeightTest {

    @Test
    public void test() throws InstantiationException, IllegalAccessException {
        
        FlyWeight flyWeight=new FlyWeight();
        FlyWeight.FlyWeightFactory factory=flyWeight. new FlyWeightFactory();
        
        
        FlyWeight.AbstractShape circle=factory.lookUp(FlyWeight.Circle.class);
        FlyWeight.AbstractShape shape=factory.lookUp(FlyWeight.Shape.class);
        
        assertEquals("shape", shape.draw());
        assertEquals("circle", circle.draw());
        
    }

}

7. Proxy

Actors:
  1. remote object
  2. local proxy class which has the same interface as remote object
  3. local client, which works with proxy as like it is remote object
  Goal : make client independent of remote object and connection. 
  Also proxy object can add some addition functionality, checking and other stuff.

Main class:

public class Proxy {
    
    interface Drawable {
        String draw();
    }
    
    public class RealImplementation implements Drawable {

        @Override
        public String draw() {
            return "real draw";
        }
        
    }
    
    public class ProxyImplementation extends RealImplementation {
        
        RealImplementation realImplementation=new RealImplementation();

        @Override
        public String draw() {
            // do some logic
            return realImplementation.draw();
            // do some logic
        }
        
    }

}

Test class:

public class ProxyTest {

    @Test
    public void test() {
        Proxy proxy=new Proxy();
        Proxy.RealImplementation remoteObject=proxy. new ProxyImplementation();
        assertEquals("real draw", remoteObject.draw());
        
    }

}