3

So almost every post I read about oop by purists, they keep stressing about how using static methods is anti pattern and breaks the testability of the code. On the other hand every time I look for some example code using factories (irrespective of programming language) specially for the purpose of object construction, I see a static method in the factory class returning the constructed object. (pseudo code below)

class ProductFactory() {

    public static function make(string name): Product
    {
        if(name contains TV)
            return new TVProduct(name)
        else 
            return new HomeAppliance(name);
    }
}

product = ProductFactory->make('LCD TV');

To me this looks perfectly fine because ultimately I want an instance of the object and not the instance of factory as will be the case below.

productFactory = new ProductFactory();
product = productFactory->make('LCD TV');

My question is two fold here.

1- What is the real way of using factories? is static method in a factory the proper & accepted way to use them?

2- How do we write unit tests for a factory that uses a static method ?

I hope my understanding of using factories for object construction is not flawed at fundamental level.

2

There are actually two different patterns which have "factory" in their name, and they serve different purposes:

  • The factory method or static factory pattern is where you use a static method instead of a constructor to provide a more meaningful name and/or a more convenient way to construct an object. It is also possible to return a different subtype (not possible with a constructor) however you are still coupled to all the subtypes at compile time.

  • The abstract factory pattern is where you define a factory interface so that your clients are completely decoupled from the actual implementation at compile time. You then pick a factory implementation at runtime and clients are able to create objects through the interface without being coupled to any concrete types.

With regard to unit testing, static factory methods are exactly the same as direct constructor calls: they cannot be mocked out (without resorting to voodoo magic) but you generally use them with types that you don't care about mocking anyway, such as value objects. For anything that is more complex than that (especially those involving external dependencies), you want to create a factory interface and inject that into the client (and mock out the factory in your unit test).

1

There's plenty of examples of static methods in otherwise 'good' code, but yes generally using statics is considered bad practice. One of the main arguments as you touch on here is that it makes testing hard.

so to answer your questions in reverse order...

  1. how do you write unit tests?

Well you can test the factory itself no probs, but can you test something that uses the factory? Or something that uses the object returned internally by the factory, where you want to mock that object?

I wont say its impossible, but its impossible without tricks.

  1. should my factories use static methods?

No. The easiest solution to the potential problems statics can cause is simply not to use statics. Your code then changes from

product = ProductFactory->make('LCD TV');

to

product = this.injectedIProductFactory->make('LCD TV');

Not a huge price to pay in the scheme of things.

  • I recommend not calling the field "injected" though. Just call it productFactory. – user253751 Feb 13 at 11:35
  • 2
    unless you are writing example code and want to indicate that its been injected........ – Ewan Feb 13 at 11:37
1

Alternatively to the approach suggested in another question, there could be a bit more hardcoded but still "abstract" code:

class ProductFactory() {

    // here factories are injected; could be real
    public ProductFactory(ITVProductFactoru tvProductFactory, IHomeApplianceFactory homeApplianceFactory)
    {
        this->tvProductFactory = tvProductFactory;
        this->homeApplianceFactory = homeApplianceFactory;
    }

    public make(string name): Product
    {
        if(name contains TV)
            return this->tvProductFactory->make(name)
        else 
            return this->homeApplianceFactory->make(name);
    }
}

So in the composition root you don't have to have the selection logic, it's moved to abstract code and can be tested for example.

0

You answered your own question

every time I look for some example code

When you look for examples you get simplified code for the sake of explaining it, not for using it in production code.

A full example of the above w/o using static factory to simplify it, would usually require you to

  • define an interface
  • define an implementation of that interface
  • setup DI/IoC container
  • use writing multiple providers, that gets injected into this implementation
  • implement each provider specific for a type to be resolved by that type (i.e. TVProductProvider handling instantiation and initialization of TVProduct type, same for HomeApplianceProvider and HomeAppliance
  • Register these provides with DI/IoC
  • implement you factory to iterate over this providers and determin the one which can handle a specific product (i.e. productProvider->canHandle(name) and if true calling productProvider->create(...) with all necessary providers

This alone requires multiple pages of example code and explainations, not including the actual example the post or tutorial was handling. So most tutorials simplify it.

Its same as tutorials provide code like

Connection connection = new Connection("server=localhost;user=root;password=p45$w0rD");
... // some query

Its there to explain the surrounding code not to suggest you "should hard-code connection strings into your source".

Common sense forbids that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.