Factory Pattern
20 May 2015
From my Java best practices training, my instructor gave us an example of the factory pattern using Shape object with draw() method. The Shape interface is further implemented by a base class called ShapeFactory which decides what kind of shape it is going to create using some business intelligence you put into the factory.
The example is spot on but I found another good example from our hands-on exercise which I'm about to share. Not just because I'm a Star Wars fan but the way factory is being used.
The Robot
package com.robots;
import java.awt.Color;
import java.awt.Point;
import java.util.List;
import com.robots.parts.Part;
public interface Robot {
void move(int distance, Direction direction);
List<Part> getParts();
String getName();
Point getXY();
void setXY(Point p);
double dist(Robot r2);
Color getColor();
int getSerial();
}
The Robot Factory
package com.robots;
public final class RobotFactory {
public static Robot createRobot() {
Robot robot = null;
if (Math.random() > 0.5) {
robot = new C3PO();
} else {
robot = new R2D2();
}
return robot;
}
}
The Basic Robot
package com.robots;
import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.robots.parts.Part;
public abstract class BasicRobot implements Robot {
// All Robots share the same fuel source.
private static final Fuel fuel = new Fuel();
// All robots share the same 'force'.
private static final Force theForce = new Force();
private Color color;
private String name;
// x and y range from 0 to 199.
private int x = (int) (Math.random() * 200);
private int y = (int) (Math.random() * 200);
protected List<Part> parts = new ArrayList<Part>();
private static int meetingPoint = 50;
public final static AtomicInteger speed = new AtomicInteger(10);
/**
* Distance from another Robot
*/
public double dist(Robot r2) {
Point p1 = getXY();
Point p2 = r2.getXY();
return Math.sqrt(Math.pow(p1.getX() - p2.getX(), 2) + Math.pow(p1.getY() - p2.getY(), 2));
}
public static Fuel getFuel() {
return fuel;
}
public static Force getTheForce() {
return theForce;
}
public static int getSpeed() {
return speed.get();
}
public static void setSpeed(int speed) {
BasicRobot.speed.set(speed);
}
public Color getColor() {
return color;
}
public String getName() {
return name;
}
public List<Part> getParts() {
return parts;
}
boolean spin = false;
protected static ExecutorService threadPool = Executors.newCachedThreadPool();
public void move(final int distance, final Direction direction) {
threadPool.submit(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < distance; i += 1) {
synchronized (fuel) {
synchronized (theForce) {
theForce.reduce();
fuel.reduce();
}
}
switch (direction) {
case EAST:
x = (x + 1) % 200;
break;
case WEST:
x = (200 + x - 1) % 200;
break;
case NORTH:
y = (200 + y - 1) % 200;
break;
case SOUTH:
y = (y + 1) % 200;
break;
}
}
Thread.sleep(50 / getSpeed());
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Ending Force is " + BasicRobot.getTheForce().getForceStrength());
System.out.println("Ending Fuel is " + BasicRobot.getFuel().getAmount());
System.out.println(getName() + " Done!");
}// End of finally block.
}
});
}
public Point getXY() {
return new Point(x, y);
}
public void setXY(Point p) {
x = (int) p.getX();
y = (int) p.getY();
}
public void setColor(Color color) {
this.color = color;
}
public void setName(String name) {
this.name = name;
}
public static int getMeetingPoint() {
return meetingPoint;
}
}
C3PO
package com.robots;
import java.awt.Color;
import java.util.concurrent.atomic.AtomicInteger;
import com.robots.parts.Motor;
import com.robots.parts.Pulley;
public final class C3PO extends BasicRobot {
private static AtomicInteger lastSerial = new AtomicInteger(0);
private final int serial;
public C3PO() {
parts.add(new Motor(485575, "Lucinet silent motor - leg", 24));
parts.add(new Motor(485576, "Lucinet silent motor - leg", 24));
parts.add(new Motor(485577, "Lucinet silent motor - neck", 24));
parts.add(new Motor(485578, "Lucinet silent motor - arm", 24));
parts.add(new Motor(485579, "Lucinet silent motor - arm", 24));
parts.add(new Pulley(485579, "Lucinet pulley system", 100));
setColor(new Color(251, 232, 123));
// Using "lastSerial++" would be unsafe since lastSerial is shared.
serial = lastSerial.incrementAndGet();
setName("C3PO " + serial);
}
public int getSerial() {
return serial;
}
public void speak() {
System.out.println("I am C3PO, human cyborg relations droid!");
}
}
R2D2
package com.robots;
import java.awt.Color;
import java.util.concurrent.atomic.AtomicInteger;
import com.robots.parts.Motor;
import com.robots.parts.Pulley;
import com.robots.parts.Wheel;
public final class R2D2 extends BasicRobot {
private static AtomicInteger lastSerial = new AtomicInteger(0);
private final int serial;
public R2D2() {
parts.add(new Motor(123456, "Chubb high torque motor", 120));
parts.add(new Pulley(334563, "Low resistance pully", 100));
parts.add(new Wheel(884457, "Rubber skinned alloy wheel", 200));
parts.add(new Wheel(884458, "Rubber skinned alloy wheel", 200));
parts.add(new Wheel(884459, "Rubber skinned alloy wheel", 200));
setColor(new Color(98, 98, 249));
// Using lastSerial++ would be unsage since lastSerial is shared.
serial = lastSerial.incrementAndGet();
setName("R2D2 " + serial);
}
public int getSerial() {
return serial;
}
public void beep() {
System.out.println("bi bi bib be bi bi be bi");
}
}