Skip to content

Instantly share code, notes, and snippets.

@DavidGinzberg
Last active November 16, 2015 20:54
Show Gist options
  • Save DavidGinzberg/b9cb42c9748122146aca to your computer and use it in GitHub Desktop.
Save DavidGinzberg/b9cb42c9748122146aca to your computer and use it in GitHub Desktop.
Design pattern labs

Factory Method pattern

I: Employee factory:

  • Write an abstract Employee class with name, type, and payment attributes (and corresponding accessor functions).
  • Extend Employee with at least two child classes that represent types of employees (e.g.: salaried, hourly, contract, permanent, etc)
  • Create an EmployeeFactory class with a makeEmployee method that takes two Strings (employee name and employee type) and returns an Employee object constructed from the corresponding child class based on the type parameter.

II: Logger Factory

  • create an abstract Logger class with abstract methods error, warn, info, debug (each method should take a single String argument — the message to be logged).
  • Extend Logger in at least two child classes (such as ConsoleLogger, EventLogger, ErrorLogger, or FileLogger) and implement the abstract methods.
  • Create a LoggerFactory object with a createLogger method that returns a new Logger of the type requested.
  • Request at least two different loggers in your main method and use them to log a few messages. (at different log levels if appropriate)

Note:

  • ConsoleLogger should log messages to the console (prefixed by log level e.g.: “INFO: ”)
  • FileLogger should log messages to a file. for this example a hardcoded zipcode.log file in the current directory is fine.
  • ErrorLogger should only log error level messages. calling its other logging methods should result in an error.

Singleton Pattern

III: MySingleton

Create a final class called MySingleton with:

  • a private constructor
  • a private static instance field (of type MySingleton)
  • a getInstance method that returns instance (if instance is null, it assigns it to a new MySingleton first)

Test that the constructor cannot be called and that getInstance returns the same instance no matter how many times it is called.

Prototype Pattern

IV: Simple Prototype

Look over the following code:

class CustomPart{
  int uniqueNumber;
  public CustomPart(int x){
    uniqueNumber = x;
    try{
      Thread.sleep(4000);
    }catch(InterruptedException e){
      System.out.println("Sleep interrupted");
    }
  }
  
  public int getValue(){ return uniqueNumber;}
}

The CustomPart object takes a long time (about 4 seconds) to create. If we want to create ten of them that long-running constructor is going to slow down our program quite a bit. Modify CustomPart to use the Prototype pattern.

CustomPart should have a public clone method that returns a duplicate of itself.

Once CustomPart is prototypeable, create a ProductionFacility class which takes a CustomPart in its constructor and has a massProduce method that produces clones of the CustomPart.

In a main method, demonstrate that creating ten or more identical CustomParts is quick using ProductionFacility

Flyweight Pattern

V: Flyweight ShapeFactory

Create a Shape interface with three child classes: Circle, Square, and EquilateralTriangle.
Shape should provide a getDimensions method.
Each Shape subclass should have the following private fields (set with the constructor):

  • Circle: radius
  • Square: sideLength
  • Triangle: sideLength

Create a FlyweightShapeFactory class with createCircle, createSquare and createTriangle methods.

Each method in FlyweightShapeFactory should take a parameter and create the requested shape with that parameter.
Use the FlyweightShapeFactory to generate at least ten different shapes and add them all to an instance of the Canvas class below, then call the draw method to "draw" all of the shapes contained in the Canvas (It will just print their details to the console in this exercise).

 class Canvas{
	private static Canvas instance = null;
	private class coordTuple{
		Shape shape;
		int xPos, yPos;

		public coordTuple(Shape s, int x, int y){
			shape = s;
			xPos = x;
			yPos = y;
		}

		public String toString(){
			return "" + shape.getClass().getName() + " at: (" + xPos + "," + yPos + ")";
		}
	}

	ArrayList<coordTuple> contents;

	public static Canvas getInstance(){
		if(instance == null){
			instance = new Canvas();
		}
		return instance;
	}

	private Canvas(){
		contents = new ArrayList<>();
	}

	/**
	 * addShape method adds a shape to the canvas
	 * at the given coordinates
	 * @param s	The Shape object to add
	 * @param x	the x coordinate of the shape
	 * @param y	the y coordinate of the shape
	 **/
	public void addShape(Shape s, int x, int y){
		contents.add(new coordTuple(s, x, y));
	}

	public String toString(){
		String output = "";
		for(coordTuple t:contents){
			output = output + t.toString() + "\n";
		}
		return output;
	}

	public void draw(){
		System.out.print(this.toString());
	}
}

Make it flyweight

All of these shapes don't need to be unique objects when they have the same values. Refactor the three methods in FlyweightShapeFactory to create a new object only if a shape of the requested size and type has not already been created. If one has already been created at the requested size, provide that object again.

Decorator Pattern

VI: ShapeDecorators

In this lab you will expand upon the Shape hierarchy created in part V. Start by adding a draw method to the Shape parent class, and implementing it on each child class. For this lab the draw method can return a string describing the shape (in a more mature system, this method might return a set of points that represent the shape on a coordinate plane)
Now that the shape hierarchy includes a draw method, it's time to add a few Decorators. First, extend the root node of the class hierarchy with an AbstractShapeDecorator class. The AbstractShapeDecorator should have a constructor that takes a Shape object as an argument, and stores that in a protected field (suggested names for that field include "decorated_shape" or "target", but call it something that makes sense to you.) Decorators should override the draw method to append or prepend descriptive text for the decorator (e.g.: a ColoredShapeDecorator may result in text such as "A red circle." or "A blue square")
Next, extend the AbstractShapeDecorator with at least two concrete decorator classes. Decorator classes should redefine the draw method to call the decorated shape's draw method, and then modify the result.
Add at least three decorated shapes to the Canvas used in the Flyweight lab, and at least one shape that has been decorated with multiple decorators. Draw the canvas after the shapes have been added.

Facade Pattern

VII: DisplayFacade

Build a class called DisplayFacade that handles the entire process of creating shapes, decorating them, adding them to a canvas, and drawing the canvas. The DisplayFacade object should provide two methods: drawShape and clearCanvas
The drawShape method should take four arguments:

  • type - an enum value that represents which kind of shape to draw
  • xPosition - the x position to draw the shape
  • yPosition - the y position to draw the shape
  • options - a Map of enum (decorator names) to boolean values (true if that decorator is used)

When drawShape is called it should create the requested shape (or request it from a factory) and decorate it according to the options, then add it to the canvas at the specified coordinates and draw the canvas with the new shape in it.
The clearCanvas method should remove all shapes from the canvas and draw it. You may need to add a method to the Canvas class to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment