I couldn't understand the role of defining an abstract class / interface for the factory class, which is something i always see in all tutorials on the web. Can somebody please put some light on the importance of CreatorInterface ? Reference UML Diagram of the Factory Pattern
To put in code form, here's what i have :
Code Example 1
// Product
public abstract class Vehicle
{
public string VehicleType { get; set; }
}
// Concrete Product
public class Bike : Vehicle
{
public Bike()
{
VehicleType = "Two Wheeler";
}
}
// Concrete Product
public class Car : Vehicle
{
public Car()
{
VehicleType = "Four Wheeler";
}
}
// Concrete Factory
public class VehicleFactory
{
public Vehicle GetVehicle(string VehicleType)
{
if (VehicleType == "Bike")
return new Bike();
else if (VehicleType == "Car")
return new Car();
else
return null;
}
}
// Client class
public class ClientClass
{
public void Main()
{
VehicleFactory VehicleFactoryObj = new VehicleFactory();
Vehicle BikeObj = VehicleFactoryObj.GetVehicle("Bike");
Vehicle CarObj = VehicleFactoryObj.GetVehicle("Car");
}
}
The above code doesn't contain any abstract class for the 'VehicleFactory' class. But it works fine. Now, what can be the reasons for adding an abstract class for the 'VehicleFactory' ? In my view adding an abstract class will make sense for the Abstract Factory method. [Please correct me if i'm wrong]
Definition by GoF :
Define an interface for creating an object, but let subclasses decide which class to instantiate. The Factory method lets a class defer instantiation it uses to subclasses.
As far as i could understand, the core problem statement behind the pattern is that you want to create instances of different classes, without exposing the creation logic to the consumer. Please let me know if i'm getting anything wrong here. I am a little confused here too, because of the examples i see on the web. For e.g on Wiki, the Php and C# examples. I could digest the requirement of the pattern in C# example, but not in PHP example. Anyways, below statements will help you to understand my question clearly.
For instance, we have two vehicle classes Bike and Car in our library, and both of them has vehicle model number. The Bike model number starts with "BK" and car model numbers start with "CR". Now, we wish to return instance of either of the classes depending of the Vehicle Model Number, without exposing the logic to the client. [Note This is an updated scenario, i am putting up since the earlier one had a weak logic of deciding the class, and created confusion over the use of string]
So we can create a vehicle factory class, which exposes a static method that returns the appropriate vehicle instance.
If selection logic is to be known to the client, then i might not have needed the pattern itself. So, the could would look like :
Code Example 2
// Product
public abstract class Vehicle
{
public int NumberOfWheels { get; set; }
}
// Concrete Product
public class Bike : Vehicle
{
public Bike()
{
NumberOfWheels = 2;
}
}
// Concrete Product
public class Car : Vehicle
{
public Car()
{
NumberOfWheels = 4;
}
}
// Client class
public class ClientClass
{
public void Main()
{
String ModelNumber = "BK-125";
Vehicle CurrentVehicle;
if (ModelNumber.Contains("BK"))
{
CurrentVehicle = new Bike();
}
else if(ModelNumber.Contains("CR"))
{
CurrentVehicle = new Car();
}
}
}
The Factory Pattern let's me simply hide the creational logic from the client by creating a factory. Thus the Client now just needs to call the Factory's create method, and he'll get the appropriate class instance in return. Now the code will look like.
Code Example 3
// Product
public abstract class Vehicle
{
public int NumberOfWheels { get; set; }
}
// Concrete Product
public class Bike : Vehicle
{
public Bike()
{
NumberOfWheels = 2;
}
}
// Concrete Product
public class Car : Vehicle
{
public Car()
{
NumberOfWheels = 4;
}
}
// Concrete Factory
public class VehicleFactory
{
public Vehicle GetVehicle(string ModelNumber)
{
if (ModelNumber.Contains("BK"))
return new Bike();
else if (ModelNumber.Contains("CR"))
return new Car();
else
return null;
}
}
// Client class
public class ClientClass
{
public void Main()
{
VehicleFactory VehicleFactoryObj = new VehicleFactory();
Vehicle BikeObj = VehicleFactoryObj.GetVehicle("BK-125");
Vehicle CarObj = VehicleFactoryObj.GetVehicle("CR-394");
}
}
Now the question comes about the abstract factory class
One benefit of adding an abstract factory class, which i understood from the discussion is that the Client will then be able to override the 'GetVehicle' method to override the logic. For a case where he might have created more vehicle classes for example a 'Truck'. But even in this case, if he want's to override the factory method for all three namely Bike, Car and Truck, he will not be have the entire logic with him as the logic for Bike and Car creation is written in Factory method. Although he will be able to create a new logic for all his new vehicle types. Can someone please put some light on this ?
I more point i want to make here is that This question is regarding the Factory Pattern, i do understand that Abstract Factory pattern will require an Abstract Factory, since in Abstract Factory pattern we're creating Factory of Factories. But in Factory pattern we just have a factory of objects, then why do we need an interface for a factory ?
Thanks in advance !! :-)
@Yair Halberstadt "...Why should i prefer the Factory method over the Static Factory ...". Both serve different purpose. Static factory is a code block which (just) collects the instantiation code for an object hierarchy (it is easy to get convinced about the name). But its nature is static (though can be written at instance level) meaning it gets bound at compile time. off course we can extend static factory but mainly as a patch code. (mostly not preferred at framework level for clients to extend.)
In contrast Factory method is useful for writing common business logic without specifying the concrete beneficiary types which clients will write on later dates.
A fictitious example (with assumption of universal Tax computation)-
public abstract class TaxComputer {
protected abstract Calculator getCalculator();// Factory method
public void registerIncome(){
//...
}
public Amount computeTax(){
Calculator alculator = getCalculator();
//... Tax computation logic using abstract Calculator
// Note: Real Calculator logic has not been written yet
return tax;
}
}
public interface Calculator {
Amount add(Amount a, Amount b);
Amount subtract(Amount a, Amount b);
Amount multiply(Amount a, double b);
Amount roundoff(int nearestAmount);
// ...
}
My all Tax rule implementations are referring to abstract Calculator for operations using Amount. It requires only abstract Calculator at this time. Once the Tax computer is ready, It can be published for clients to extend (With extension point at abstract classes and hook factory method).
Specific client can extend it to computations for Yen (Does not have decimal point) or Dollar/ Pound etc or even calculators which round off (e.g. to next 10 Rupees) after every operation as per local rule.
Same way USDollarTaxCalculator will extend it with their own rules for operations (but can not and need not redefine Tax rules)
public class YenTaxComputer extends TaxComputer {
@Override
protected Calculator getCalculator() {
return new YenCalculator();
}
}
public class YenCalculator implements Calculator {
@Override
public Amount add(Amount a, Amount b) {
/*Yen specific additions and rounding off*/
}
@Override
public Amount subtract(Amount a, Amount b) {/*...*/ }
@Override
public Amount multiply(Amount a, double b) {/*...*/ }
@Override
public Amount roundoff(int nearestAmount) {/*...*/ }
}
In factory method point is not about hiding creation logic but keeping extensions possible for clients.
The client will look something like
public class TaxClient {
public static void main(String[] args) {
TaxComputer computer = new YenTaxComputer();//
computeTax(computer);
}
/** A PLACE HOLDER METHOD FOR DEMO
*/
private static void computeTax(TaxComputer computer) {
Amount tax = computer.computeTax();
Amount Payment = ...
//...
}
}
Points to be noted here