Chapter 29. Factory


© Jennifer M. Kohnke

The man who builds a factory builds a temple.

Calvin Coolidge (18721933)

The Dependency-Inversion Principle (DIP) (Chapter 11) tells us that we should prefer dependencies on abstract classes and avoid dependencies on concrete classes, especially when those classes are volatile. Therefore, the following snippet of code violates this principle:

Circle c = new Circle(origin, 1);


Circle is a concrete class. Therefore, those modules that create instances of Circle must violate DIP. Indeed, any line of code that uses the new keyword violates DIP.

There are times when violating DIP is mostly harmless, which is pretty good coverage. The more likely a concrete class is to change, the more likely that depending on it will lead to trouble. But if the concrete class is not volatile, depending on it is not worrisome. For example, creating instances of string does not bother me. Depending on string is very safe because string is not likely to change any time soon.

On the other hand, when we are actively developing an application, many concrete classes are very volatile, so depending on them is problematic. We'd rather depend on an abstract interface to shield us from the majority of the changes.

The FACTORY pattern allows us to create instances of concrete objects while depending only on abstract interfaces. Therefore, it can be of great assistance during active development when those concrete classes are highly volatile.

Figure 29-1 shows the problematic scenario. We have a class named SomeApp that depends on the interface Shape. SomeApp uses instances of Shape solely through the Shape interface and does not use any of the specific methods of Square or Circle. Unfortunately, SomeApp also creates instances of Square and Circle and thus has to depend on the concrete classes.

Figure 29-1. An app that violates DIP to create concrete classes


We can fix this by applying the FACTORY pattern to SomeApp, as in Figure 29-2. Here, we see the ShapeFactory interface, which has two methods: MakeSquare and MakeCircle. The MakeSquare method returns an instance of a Square, and the MakeCircle method returns an instance of a Circle. However, the return type of both functions is Shape.

Figure 29-2. Application of FACTORY to SomeApp


Listing 29-1 shows what the ShapeFactory code looks like. Listing 29-2 shows ShapeFactoryImplementation.

Listing 29-1. ShapeFactory.cs

public interface ShapeFactory {   Shape MakeCircle();   Shape MakeSquare(); }

Listing 29-2. ShapeFactoryImplementation.cs

public class ShapeFactoryImplementation : ShapeFactory {   public Shape MakeCircle()   {     return new Circle();   }   public Shape MakeSquare()   {     return new Square();   } }

Note that this completely solves the problem of depending on concrete classes. The application code no longer depends on Circle or Square, yet it still manages to create instances of them. It manipulates those instances through the Shape interface and never invokes methods that are specific to Square or Circle.

The problem of depending on a concrete class has been moved. Someone must create ShapeFactoryImplementation, but nobody else ever needs to create Square or Circle. ShapeFactoryImplementation will most likely be created by Main or an initialization function attached to Main.




Agile Principles, Patterns, and Practices in C#
Agile Principles, Patterns, and Practices in C#
ISBN: 0131857258
EAN: 2147483647
Year: 2006
Pages: 272

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net