Creational patterns abstract the instantiation process, because sometimes using new
is just not cool enough. This is because instantiation can often times lead to coupling problems. Coupling problems are not cool.
When you see “new”, think “concrete”.
– Head First Java
While this is a play on words, it is valid. Concrete in this case means “hard to move”.
Why is using new
bad? Imagine having to go back and change all the places in your code where you have “newed up”.
Being able to change an object at runtime is where things get cool and factory comes into play.
Simple “Plain Jane” Factory
I had a problem and tried to use Java. Now I have a ProblemFactory.
– Unknown
Often times it’s best to start with the most simple example possible: building a simple status code object.
public class StatusCode
{
public StatusCodeFactory(int status, bool isSuccess)
{
this.status = status;
this.isSuccess = isSuccess;
}
public static StatusCode createStatusCode(int status, bool isSucess)
{
return new StatusCode(status, isSuccess);
}
}
In simple cases like this, we could easily get away with a factory. Complex objects can be difficult to manage and factories provide ways to provide clear “instructions” on how to new up.
Runtime AKA “Bus Down” Factory
But the problem with our previous factory is that is can’t really change. It’s static and in most cases we want the ability to alter our objects after we run the code!
Using if statements we can use logic so that we can create different objects “on the fly” (aka runtime).
public class StatusCodeFactory {
public StatusCode createStatusCode(String type) {
StatusCode status = null;
if(type.equals("404")) {
status = new ErrorStatusCode();
} else if (type.equals("200")) {
status = new OKStatusCode();
}
}
}
This is very interesting, but how do we actually use this?
Like good little developers, we wire it up in the constructor!
public class Controller {
StatusCodeFactory factory;
public Controller(StatusCodeFactory factory) {
this.factory;
public IActionResult ErrorPage() {
statusCode = factory.createStatusCode("404");
return View(statusCode);
};
}
Abstract Factory
There is levels to this shit, homie!
– Steve Smith
The code above is wonderful but sometimes we want more control over the objects. Let’s say we want our status code to have unique properties too.
Currently, our factory creates objects but only in a predefined way (similar to a real factory). Unlike the physical world, we can have our cake and eat it too. We can mass produce objects AND have give them granularity.
public abstract class StatusCodeFactory {
abstract IActionResult createStatusCode(String type);
}
If we decide to use this abstract class, we now are forced to create our own createStatusCode()
.
We now can create different varieties of our status code in our subclasses.
public StatusCode createStatusCode(String type) {
StatusCode status = null;
if(type.equals("404")) {
status = new ErrorStatusCode();
} else if (type.equals("200")) {
status = new OKStatusCode();
}
}
Why even do this when we could easily just sub class it and say screw abstract classes?
You could easily do that, actually. In fact, most people end up “abstracting” inadvertently by creating a base object like “BaseStatusCodeFactory”. The abstract class just provides more rules and clarity.
This is why it’s called an “abstract class”.
Abstract-ception
We can even abstract more of our code away. Let’s abstract the StatusCode:
public abstract class StatusCode {
String status = "404";
bool isSuccess = false;
}
This abstract class will function similar to our “defaults”. Behind the scenes, we no longer have to worry providing every instance of our code with “defaults”. We can abstract away simple things and worry about the granularity of each status code.
public class AuthenticationStatusCode extends StatusCode {
bool isAuthenticated;
}
Individual status codes can receive all our “defaults” and we can worry about individual authentication scenarios.
Dependency Inversion Principle
Congratulations. You’ve just learned one the great design principles known as “Dependency Inversion Principle”. This is very similar to the saying “program to an interface”.
DI principle simple means depend on abstract classes (or interfaces). Unless you are coding something very simple, don’t go around newing up everything in your code. Relying to heavily on concrete classes will not enforce rules or provide ways to abstract code out.
Conclusion and Guidelines
In our example, there are countless combinations of status codes and allowing people to create infinite variations will cause your code base to become a total mess.
Here are some guidelines:
- Unless your code base is simple, stay away from newing up code (especially in properties)
- Try no to inherit from a concrete class (just use abstract classes for base classes even if its not technically abstracting)
- Don’t override methods of base classes
Just like any form of “principles”, you will have cult members who try way to hard to shove design patterns into their shitty code.
Always remember to have fun and KISS (keep it simple, stupid)!