Showing posts with label design pattern. Show all posts
Showing posts with label design pattern. Show all posts

Tuesday, January 24, 2012

The Bridge pattern

Problem: Draw rectangles and circles with either of two drawing programs without causing an explosion in the number of classes.
Solution: Decoupling implementation from the objects that use them.
public abstract class AbstractShape {
    private DrawingProgram dp;
    public abstract void draw();
    public AbstractShape(DrawingProgram dp) {
        this.dp = dp;
    }
    public void drawLine() {
        this.dp.drawLine();
    }
    public void drawCircle() {
        this.dp.drawCircle();
    }
}
public class Rectangle extends AbstractShape {
    public Rectangle(DrawingProgram dp) {
        super(dp);
    }
    @Override public void draw() {
        drawLine(); drawLine(); drawLine(); drawLine();
    }
}
public class Circle extends AbstractShape {
    public Circle(DrawingProgram dp) {
        super(dp);
    }
    @Override public void draw() {
        drawCircle();
    }
}
public interface DrawingProgram {
    void drawLine(); // implicitly public
    void drawCircle();
}
public class DrawingProgram1 implements DrawingProgram {
    @Override public void drawLine() { ... }
    @Override public void drawCircle() { ... }
}
public class DrawingProgram2 implements DrawingProgram {
    @Override public void drawLine() { ... }
    @Override public void drawCircle() { ... }
}
public class client {
    public static void main(String[] args) {
        Drawing dp1 = new DrawingProgram1();
        Rectangle rectangle = new Rectangle(dp1);
        Drawing dp2 = new DrawingProgram2();
        Circle circle = new Circle(dp2);

        circle.draw();
        rectangle.draw();
    }
}

The Abstract Factory pattern

Problem: Instantiate families of objects.
Solution: The Abstract Factory pattern defines the interface for how to create each member of the family.
public interface WindowFactory {
    Window createWindow(); // implicitly public
}
public MsWindowFactory implements WindowFactory {
    @Override public Window createWindow() {
        return new MsWindow();
    }
}
public AppleWindowFactory implements WindowFactory {
    @Override public Window createWindow() {
        return new AppleWindow();
    }
}
public Client {
    public static void main(String[] args) {

        WindowFactory  factory;
        String osName = System.getProperty("os.name");
        if ((osName != null) && (osName.indexOf("Windows") != -1)) {
            factory = new MsWindowFactory();
        } else {
            factory = new AppleWindowFactory();
        }

        Window window = factory.createWindow();
    }
}

Monday, January 23, 2012

The Factory Method pattern

Problem: A class needs to instantiate a derivation of another class, but doesn't know which one.
Solution: The Factory Method defines an interface for creating objects, but lets subclasses decide which classes to instantiate.
public interface Logger {
    void debug(String message); // implicitly public
}
public class FileLogger implements Logger {
    @Override public void debug(String message) { ... }
}
public abstract class AbstractLoggerFactory {
    public abstract Logger createLogger(); // factory method

    public Logger getLogger() {
        Logger logger = createLogger();
        ...
        return logger;
    }
}
public class FileLoggerFactory extends AbstractLoggerFactory {
    @Override
    public Logger createLogger() {
        return new FileLogger();
    }
}
public class Client {
    private AbstractLoggerFactory factory = new FileLoggerFactory();
    public doSomething(AbstractLoggerFactory factory) {
        Logger logger = factory.getLogger();
        logger.debug("debug message");
    }
}

The Singleton pattern

Problem: Several clients need to refer to the same thing.
Solution: The Singleton pattern guarantees a class has only one instance.
// Enum singleton - the preferred approach: concise + serializable
public enum Singleton { // implicitly final
    INSTANCE; // implicitly public static final
    public void doSomething() { ... }
}

Saturday, January 21, 2012

The Visitor pattern

Problem: Determine the postage for the items in a shopping cart.
Solution: The Visitor pattern creates an external class that will use the data of the cart items to compute the postage.
public interface Visitable {
    void accept(Visitor visitor); // implicitly public
}
public class Book implements Visitable {
    @Override public void accept(Visitor visitor) {
        if (...) visitor.visit(this);
    }
}
public interface Visitor {
    void visit(Book book); // implicitly public
    void visit(CD cd);
}
public class PostageVisitor implements Visitor {
    @Override public void visit(Book book) {
        this.totalPostage += ...;
    }
    @Override public void visit(CD cd) {
        this.totalPostage += ...;
    }
    public void getTotalPostage() {
        return this.totalPostage;
    }
}
public class Client {
    public double calculatePostage() {
        PostageVisitor visitor = new PostageVisitor();
        for (Visitable item : this.items) {
            item.accept(visitor);
        }
        return visitor.getTotalPostage();
    }
}

The Adapter pattern

Problem: A system has the right data and behavior but the wrong interface.
Solution: The Adapter provides a wrapper with the desired interface.

The Facade pattern

Problem: Use a subset of a complex system.
Solution: The Facade presents a new interface of the system.