8

I'm still trying to understand design patterns here, after learning the Abstract factory pattern , I realised that this pattern will not scale well. Take a look at the uml diagram of the abstract factory pattern

uml diagram

If I have to create a new 'AbstractProductC', I will have to add an abstract method 'CreateProductC' in 'AbstractFactory' which effects the implementation of both ConcreateFactory1, ConcreateFactory2.

My question here is, does Abstract Factory pattern scale at all (or) I'm I thinking in the wrong direction here ?

thanks in advance

  • I think the diagram you presented, which looks relatively standard, has been simplified to illustrate the pattern in question. However, if you need something more complex, you could always have AbstractFactory defined just one method: CreateProduct(productType) and then have a factory within a factory that would look at the type and instantiate concrete class based on that. – DXM Dec 11 '13 at 8:05
  • @DXM That doesn't fix the problem. You would still need to change implementation of concrete factories every time you add new product. – Euphoric Dec 11 '13 at 8:36
  • Well, the only thing that would scale is actual abstract interface, but yeah, if you have N products and M ways of creating them, no matter how you slice it, you need N x M implementations, unless you go with a completely different strategery. – DXM Dec 11 '13 at 8:43
  • @Euphoric: Not necessarily. You could just have to add a factory class and register that with the abstract factory. May seem a little nitpicky, but for scaling and SRP I find adding a bit less troublesome than changing. – Marjan Venema Dec 11 '13 at 8:49
  • @MarjanVenema Now the question is if it is really a factory and not different pattern. – Euphoric Dec 11 '13 at 10:12
5

Abstract Factory scales just fine.

There is a basic principle which states that a class should do one thing well. Your problem here is you are trying to make many classes do many things.

You don't have to stick to one abstract factory. You can (and should have) several:

AbstractProductAFactory defines the interface for producing ProductA. Your concrete implementations (ConcreteProductAFactory1, ConcreteProductAFactory2) would extend it.

AbstractProductBFactory defines the interface for producing ProductB. Your concrete implementations (ConcreteProductBFactory1, ConcreteProductBFactory2) would extend it.

If you then need a ProductC, create a new AbstractProductCFactory. No need to change any of your other factories this way.

UPDATE Ideally ProductA should represent a class of product--that is, all the products that share an interface that you're calling ProductA. In the comments I suggest that this is something like a Pizza:

interface AbstractPizzaFactory {
    public Pizza buildPizza(List<Topping> toppings);
}


class ThinCrustPizzaFactory implements AbstractPizzaFactory {
    public Pizza buildPizza(List<Topping> toppings){

        ...

    }
}

class DeepDishPizzaFactory implements AbstractPizzaFactory {
    public Pizza buildPizza(List<Topping> toppings){

        ...

    }
}

And so on. Adding a PanPizzaFactory won't affect any of the other classes--it's just a new concrete implementation of the PizzaFactory. If you have products that aren't pizzas--sandwiches, for example, that's where you create another abstract factory (e.g., AbstractSandwichFactory).

The real point is, you wouldn't want to have a abstract factory that builds two very different types of product with two different "build" methods. Group them as logically as you can so that they share an interface, and then create an abstract factory that defines how concrete factories should build implementations of that interface.

  • 4
    You're kidding, right? What if your company makes 256 products? Or 1024? – Robert Harvey Dec 10 '13 at 19:30
  • @RobertHarvey - I'm assuming that ProductA is a class of products--suppose it's a AbstractPizzaFactory. This can have a concrete ThinCrustPizzaFactory, a concrete PanPizzaFactory, and a concrete DeepDishPizzaFactory. Likewise, sandwiches would be built by subtypes of a AbstractSandwichFactory. This is different from and AgrstractFactory with both a buildPizza and a buildSandwich method. – Matthew Flynn Dec 10 '13 at 21:44
  • @RobertHarvey - Meanwhile, subtle variations in products (like toppings) might be something that can be handled seperately. Perhaps your factory method would be AbstractPizzaFactory.buildPizza(List<Topping> toppings). – Matthew Flynn Dec 10 '13 at 21:47
  • You might want to make those things clear in your answer. – Robert Harvey Dec 10 '13 at 21:47
  • @RobertHarvey - updated – Matthew Flynn Dec 10 '13 at 22:04
4

The problem with scaling is that code can scale in many different ways. The problem you are having is simply caused by need to scale in a direction, that design pattern is not intended for. In case of Abstract Factory pattern, it is meant to scale in a way of adding new concrete factories, but adding new product causes big structural changes.

One of the points of software design and architecture is to identify most likely directions the code will scale and pick patterns based on those likely directions. If you identify, that adding new product is more likely than adding new concrete factory, then using Abstract Factory is not a good idea and it might be better to completely re-think the design.

  • 1
    your answer makes more sens than the rigid "ABSTRACT FACTORY SCALES FINE !" of the other guy... – Turkish Dec 11 '13 at 7:31
  • @Euphoric, as you are suggesting, Abstract factory pattern scale's in a way of adding new concrete factories, but finally the new concrete factory has to generate products, which comes down to the product creation and ultimately we should do structural changes, is that not right? – Jitendar Dec 11 '13 at 17:47
  • @Jitendar I don't understand what you mean. The point of abstract factory is that there is relatively stable family of related abstractions (ProductA, ProductB) and concrete factories create implementations of those abstractions, that too are related somehow. If possibility of adding new abstraction is higher, than adding new concrete implementations of those abstractions, then using Abstract Factory is not a good pick. – Euphoric Dec 11 '13 at 18:46
3

Yes, you are right, "abstract factory" does not scale well when you need additional abstract products.

But in a lot of real-world scenarios you have a changing number of products, but only a small, fixed number of abstract products to support. For instance, take the GUI widgets example from the wikipedia article about abstract factories. The abstract GUI factory could have a method createWidget (instead of createButton), where Widget is the "abstract product", beeing the topmost base class for a family of several dozen GUI elements. Adding new GUI widgets does in no way imply a change to the interface of the abstract factory, so none of the concrete factory`s interfaces has to be changed.

Having lots of abstract products means you will have a lot of different class hierarchies in your code. And if that's the case, you may consider to create an individual factory (or abstract factory) for each of the hierarchies.

0

Your scaling factor is a simple matter of dependency management. The more dependencies a class has - the more stable and thoughtful its API should be.

There is no problem in creating a factory that is defined by the responsibility of creating types of similar or cohesive nature. But the more classes that depend on this factory - the more strict this cohesion should be.

(Note: this can be done in a gradual way, not necessarily by a BDUF)

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.