Today our code review session has been very interesting. The debates were surrounded to static factory method. Below i have put some sample code with common mistakes and ways to improve around.
Many times i think the beauty of OOP stays with design patterns. GOF teach design patterns in terms Creational, Behavioral and Structural. We have also seen other design patterns such as Concurrent and in Java J2EE container based environments we also see Enterprise design patterns, Enterprise Integration patterns. However application and choose between design patterns, as well as correct code would need some level of reading and experience.
Many times i think the beauty of OOP stays with design patterns. GOF teach design patterns in terms Creational, Behavioral and Structural. We have also seen other design patterns such as Concurrent and in Java J2EE container based environments we also see Enterprise design patterns, Enterprise Integration patterns. However application and choose between design patterns, as well as correct code would need some level of reading and experience.
For me true elegance of design of Design Patterns stays with fundamentals such as abstraction, polymorphism and encapsulation. In many places choose between design patterns fundamentally can be based to teachings of coupling and cohesion. Algorithm performance, cosmetics of code, structure - and other biliites such as maintainability, extensibility, readability are other important aspects too.
Today's the review case, was about using Josuah Bloch’s Static Factory method to improve GOF Factory design pattern.
GOF factory design pattern is well described every where in the web using famous example different shapes such as rectangles, circles etc from the Shape interface. I am going use this popular example for the explanation below. There you see the code also repeat common programming mistakes which were revealed during the review. Those would be lovely for junior OOP developers to understand some pragmatic programming best practices.
Today's the review case, was about using Josuah Bloch’s Static Factory method to improve GOF Factory design pattern.
GOF factory design pattern is well described every where in the web using famous example different shapes such as rectangles, circles etc from the Shape interface. I am going use this popular example for the explanation below. There you see the code also repeat common programming mistakes which were revealed during the review. Those would be lovely for junior OOP developers to understand some pragmatic programming best practices.
The code below we have two factories. One is Gang Of Four Shape factory and the other is Static Shape Factory. First we would take GOF Shape factory class and will try to improve that.
A good improvement to GOFShapeFactory class should be replacing if else checks with a Swich Case instead String Comparison. Next we would think in terms of code structure. Wouldn't that be nice if we could produce shape Objects such as Rectangle Circle Triangle etc directly with out this switch case loop. How do we do that with out creating GOFShapeFactory reference objects for multiple times? This is where Static Factory pattern would come in handy. We would think of a Static Class method and getting new objects as in StaticShapeFactory class below. Additional benefit of doing that could be improved readability and concise code. Additionally that would create a reference Factory object in the Heap. That reduce coupling of object at runtime. Since it is Class method, you will call the method by class name, instead object reference. Those static create methods will initialize the objects in their respective ways.
You can still improve the below code … ?
public interface Shape {
void draw();
}
public class Rectangle implements Shape {
public Rectangle() {
// TODO Auto-generated constructor stub
}
@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("you are drawing a Rectangle");
}
}
public class Circle implements Shape{
public Circle() {
// TODO Auto-generated constructor stub
}
@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("you are drawing a Circle");
}
}
public class Square implements Shape{
public Square() {
// TODO Auto-generated constructor stub
}
@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("you are drawing a Square");
}
}
public class GOFShapeFactory {
public GOFShapeFactory() {
// TODO Auto-generated constructor stub
}
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
1) Loose Coupling.
2) Better Cohesion.
3) Better performance - no string Comparison or Switch Loops.
3) Better readability.
5) Less Verbosity.
Below is the new Factory class which is designed based to described Static factory principles. We can pretty much set the private instance variables here and cook the class in anyways you like.
public class StaticShapeFactory {
public static Shape createRectangularShape(String shapeType) {
return new Rectangle();
}
public static Shape createSquareShape(String ShapeType) {
return new Square();
}
public static Shape createCircleShape(String ShapeType) {
return new Circle();
}
}
Factory demo is the class calls the main method.
public class FactoryDemo {
public static void main(String[] args) {
GOFShapeFactory gofShapeFactory = new GOFShapeFactory();
StaticShapeFactory statShapeFactory = new StaticShapeFactory();
// get an object of Circle and call its draw method.
Shape shape1gof = gofShapeFactory.getShape("CIRCLE");
// wrong object creation for static factory
Shape shape1stat = statShapeFactory.createCircleShape("Circle");
// correct way to implement
StaticShapeFactory.createCircleShape("Circle").draw();
// call draw method of Circle
shape1gof.draw();
shape1stat.draw();
// get an object of Rectangle and call its draw method.
Shape shape2gof = gofShapeFactory.getShape("RECTANGLE");
//wrong way to call for static method.
//wrong way to call for static method.
Shape shape2stat = statShapeFactory.createCircleShape("Rectangle");
// call draw method of Rectangle
shape2gof.draw();
shape2stat.draw();
// get an object of Square and call its draw method.
Shape shape3gof = gofShapeFactory.getShape("SQUARE");
//wrong way to call for static method.
//wrong way to call for static method.
Shape shape3stat = statShapeFactory.createCircleShape("Square");
// call draw method of circle
shape3gof.draw();
shape3stat.draw();
}
}