Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Factory classes [closed]

Personally I've never understood the idea of factory classes because it seems a whole lot more useful to just instantiate an Object directly. My question is simple, in what situation is the use of a factory class pattern the best option, for what reason, and what does a good factory class look like?

like image 305
Neil Locketz Avatar asked Jan 29 '13 04:01

Neil Locketz


People also ask

Do factories violate the Open Closed Principle?

No, it doesn't violate the Open/Closed principle at all. Open/Closed means you can modify the way a system works without modifying the code that already exists. You can extend the code and use it in different ways, but the old code is still in tact and doesn't need to be re-tested.

What is the point of factory classes?

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.

What is a factory class and how does it work?

A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. In other words, subclasses are responsible to create the instance of the class.


1 Answers

Here is a real live factory from my code base. It's used to generated a sampler class that knows how to sample data from some dataset (it's originally in C#, so excuse any java faux-pas)

class SamplerFactory {   private static Hashtable<SamplingType, ISampler> samplers;    static   {     samplers = new Hashtable<SamplingType, ISampler>();     samplers.put(SamplingType.Scalar, new ScalarSampler());     samplers.put(SamplingType.Vector, new VectorSampler());     samplers.put(SamplingType.Array, new ArraySampler());   }    public static ISampler GetSampler(SamplingType samplingType)   {     if (!samplers.containsKey(samplingType))       throw new IllegalArgumentException("Invalid sampling type or sampler not initialized");     return samplers.get(samplingType);   } } 

and here is an example usage:

ISampler sampler = SamplerFactory.GetSampler(SamplingType.Array); dataSet = sampler.Sample(dataSet); 

As you see, it's not much code, and it might even be shorter and faster just to do

ArraySampler sampler = new ArraySampler(); dataSet = sampler.Sample(dataSet); 

than to use the factory. So why do I even bother? Well, there are two basic reasons, that build on each other:

  1. First, it is the simplicity and maintainability of the code. Let's say that in the calling code, the enum is provided as a parameter. I.e. if I had a method that need to process the data, including sampling, I can write:

    void ProcessData(Object dataSet, SamplingType sampling) {   //do something with data   ISampler sampler = SamplerFactory.GetSampler(sampling);   dataSet= sampler.Sample(dataSet);   //do something other with data } 

    instead of a more cumbersome construct, like this:

    void ProcessData(Object dataSet, SamplingType sampling) {   //do something with data   ISampler sampler;   switch (sampling) {     case SamplingType.Scalar:         sampler= new ScalarSampler();       break;     case SamplingType.Vector:         sampler= new VectorSampler();       break;     case SamplingType.Array:       sampler= new ArraySampler();       break;     default:       throw new IllegalArgumentException("Invalid sampling type");   }   dataSet= sampler.Sample(dataSet);   //do something other with data } 

    Note that this monstrosity should be written each and every time I need me some sampling. And you can imagine how fun it will be to change if, let's say, I added a parameter to ScalarSampler constructor, or added a new SamplingType. And this factory has only three options now, imagine a factory with 20 implementations.

  2. Second, it's the decoupling of the code. When I use a factory, the calling code does not know or need to know that a class called ArraySampler even exists. The class could even be resolved at run-time, and the call site would be none the wiser. So, consequently, I am free to change the ArraySampler class as much as I want, including, but not limited to, deleting the class outright, if, e.g. I decide that the ScalarSampler should be used for array data as well. I would just need to change the line

    samplers.put(SamplingType.Array, new ArraySampler()); 

    to

    samplers.put(SamplingType.Array, new ScalarSampler()); 

    and it would work magically. I do not have to change a single line of code in the calling classes, which could number in the hundreds. Effectively, the factory makes me in control of what and how the sampling occurs, and any sampling changes are efficiently encapsulated within a single factory class that is interfaced with the rest of the system.

like image 110
SWeko Avatar answered Oct 21 '22 20:10

SWeko