It's the same pattern, and the two diagrams are practically the same, it's just that some of the details of how the pattern is actually used are somewhat obscured, and this makes them look superficially different.
The dashed arrows represent a generalized dependency - meaning that one type somehow depends on the other, but it doesn't necessarily imply that it holds a direct reference to an instance (e.g., it could just be that the type appears as a parameter to, or as a return type of, a function).
Now, in the first picture, client code has no dependencies to (no knowledge of) concrete products or concrete factories - all the arrows from Client point only to the abstract interfaces. In other words, all client code is written only in terms of these abstract interfaces.
This is exactly the same situation as the one depicted in the second diagram, except that there the client takes the factory as a dependency through the constructor (but again, typed via the abstract interface). The fact that it's an aggregation is a detail (an implementation choice) that doesn't have any significance to the overall pattern - the important thing, and what makes it equivalent to the first diagram, is that (1) the type of the factory
field is AbstractFactory
(not any concrete factory), and (2) that the return types of the producer methods in AbstarctFactory
are all abstract products. The fact that the client uses those types corresponds to the dashed arrows in the first diagram.
For example, someOperation()
contains the line:
ProductA pa = factory.createProductA(); // Note that ProductA is the abstract type
// presumably, the remainder of the code then does something with pa
This means that Client
(which defines someOperation()
) depends on ProductA. This dependency is represented in the first diagram by the dashed line going from Client
to AbstractProductA
- it's just that this representation doesn't show exactly how this dependency occurs, just that it is there. In the second diagram, this dependency is implicit, and can be inferred from the other elements shown.
One thing that isn't shown on these diagrams is how is the concrete factory actually chosen. There's some third component that does this - it is often some kind of entry point, like the Main()
method, or some kind of root to a module, or a root to some group of collaborating objects. I.e., it happens somewhere else, where you know which concrete products you want to use.
The concrete factories themselves depend on their corresponding concrete products, so these do not have to be configured (which concrete products are used is determined by the choice of a concrete factory). Once the selection is made, the abstract reference to the factory is handed over to the client in some way; this enables the client to remain decoupled from the concrete products.
So the missing piece may look something like this:
static public void Main(string[] args)
{
// Any mention of anything concrete is confined to this line
// (and within the ConcreteFactory1 itself)
AbstractFactory factory = new ConcreteFactory1();
Client client = new Client(factory);
client.SomeOperation();
}
The choice can be hardcoded, as here, or based on an entry in a config file, or done via preprocessor directives, or dynamically determined in some way, etc. The factory instance can be handed over to the client "manually", or it could be created, injected and managed by an IoC container.