© Vaskaran Sarcar 2019
Vaskaran SarcarJava Design Patternshttps://doi.org/10.1007/978-1-4842-4078-6_5

5. Abstract Factory Pattern

Vaskaran Sarcar1 
(1)
Bangalore, Karnataka, India
 

This chapter covers the abstract factory pattern.

GoF Definition

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Note

To better understand this pattern, I suggest that you start at Chapter 24 (simple factory pattern) and then cover Chapter 4 (factory method pattern). The simple factory pattern does not fall directly in the Gang of Four design patterns, so the discussion on that pattern is placed in Part II of this book.

Concept

This is basically a factory of factories that provides one level of higher abstraction than the factory method pattern. This pattern helps us to interchange specific implementations without changing the code that uses them, even at runtime.

This pattern provides a way to encapsulate a group of individual factories that have a common theme. Here a class does not create the objects directly; instead, it delegates the task to a factory object.

The simple factory method pattern creates a set of related objects. In a similar way, since an abstract factory is basically a factory of factories, it returns factories that create a set of related objects. (I discuss the differences in detail in the “Q&A Session” section.)

Real-World Example

Suppose that we are decorating our room with two different tables: one made of wood and one made of steel. For the wooden table, we need to visit to a carpenter, and for the other table, we need to go to a metal shop. Both are table factories, so based on our demand, we decide what kind of factory we need.

In this context, you may consider two different car manufacturing companies: Honda and Ford. Honda makes models, such as CR-V, Jazz, Brio, and so forth. Ford makes different models, such as Mustang, Figo, Aspire, and so forth. So, if you want to purchase a Jazz, you must visit a Honda showroom, but if you prefer a Figo, you go to a Ford showroom.

Computer-World Example

To understand this pattern, I’ll extend the requirement in the factory method pattern. In factory method pattern, we had two factories: one created dogs and the other created tigers. But now, you want to categorize dogs and tigers further. You may choose a domestic animal (dog or tiger) or a wild animal (dog or tiger) through these factories. To fulfil that demand, I introduce two concrete factories: WildAnimalFactory and PetAnimalFactory. The WildAnimalFactory is responsible for creating wild animals and the PetAnimalFactory is responsible for creating domestic animals, or pets.

Note

The newInstance() method of javax.xml.parsers.DocumentBuilderFactory is an example of the abstract factory pattern in JDK. The newInstance() method of javax.xml.transform.TransformerFactory is another such example in this context. If you are familiar with C#, you may notice that ADO.NET has already implemented similar concepts to establish a connection to a database.

Illustration

Wikipedia describes a typical structure of the abstract factory pattern ( https://en.wikipedia.org/wiki/Abstract_factory_pattern ), which is similar to what’s shown in Figure 5-1.
../images/395506_2_En_5_Chapter/395506_2_En_5_Fig1_HTML.jpg
Figure 5-1

A typical example of an abstract factory pattern

I am going to follow a similar structure in our implementation. So, in the following implementation, I used two concrete factories: WildAnimalFactory and PetAnimalFactory. They are responsible for the creations of the concrete products, dogs and tigers. WildAnimalFactory creates wild animals (wild dogs and wild tigers) and PetAnimalFactory creates domesticated pet animals (pet dogs and pet tigers). For your ready reference, the participants with their roles are summarized as follows.
  • AnimalFactory: An interface that is treated as the abstract factory in the following implementation.

  • WildAnimalFactory: A concrete factory that implements AnimalFactory interface. It creates wild dogs and wild tigers.

  • PetAnimalFactory: Another concrete factory that implements the AnimalFactory interface. It creates pet dogs and pet tigers.

  • Tiger and Dog: Two interfaces that are treated as abstract products in this example.

  • PetTiger, PetDog, WildTiger, and WildDog: The concrete products in the following implementation.

Here the client code is looking for animals (dogs and tigers). A common usage of this pattern is seen when we compose classes using the concrete instances of the abstract factory. I have followed the same. Notice that the client class contains the composed implementation of AnimalFactory. You can explore the construction process of both pet and wild animals in the following implementation.

Class Diagram

Figure 5-2 shows the class diagram.
../images/395506_2_En_5_Chapter/395506_2_En_5_Fig2_HTML.jpg
Figure 5-2

Class diagram

Package Explorer View

Figure 5-3 shows the high-level structure of the program.
../images/395506_2_En_5_Chapter/395506_2_En_5_Fig3_HTML.jpg
Figure 5-3

Package Explorer view

Implementation

Here’s the implementation.
package jdp2e.abstractfactory.demo;
interface Dog
{
      void speak();
      void preferredAction();
}
interface Tiger
{
      void speak();
      void preferredAction();
}
//Types of Dogs-wild dogs and pet dogs
class WildDog implements Dog
{
      @Override
      public void speak()
      {
            System.out.println("Wild Dog says loudly: Bow-Wow.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Wild Dogs prefer to roam freely in jungles. ");
      }
}
class PetDog implements Dog
{
      @Override
      public void speak()
      {
                System.out.println("Pet Dog says softly: Bow-Wow.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Pet Dogs prefer to stay at home. ");
      }
}
//Types of Tigers-wild tigers and pet tigers
class WildTiger implements Tiger
{
      @Override
      public void speak()
      {
            System.out.println("Wild Tiger says loudly: Halum.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Wild Tigers prefer hunting in jungles. ");
      }
}
class PetTiger implements Tiger
{
      @Override
      public void speak()
      {
            System.out.println("Pet Tiger says softly: Halum.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Pet Tigers play in the animal circus. ");
      }
}
//Abstract Factory
interface AnimalFactory
{
      Dog createDog();
      Tiger createTiger();
}
//Concrete Factory-Wild Animal Factory
class WildAnimalFactory implements AnimalFactory
{
      @Override
      public Dog createDog()
      {
            return new WildDog();
      }
      @Override
      public Tiger createTiger()
      {
            return new WildTiger();
      }
}
//Concrete Factory-Pet Animal Factory
class PetAnimalFactory implements AnimalFactory
{
      @Override
      public Dog createDog()
      {
            return new PetDog();
      }
      @Override
      public Tiger createTiger()
      {
            return new PetTiger();
      }
}
//Client
class AbstractFactoryPatternExample {
      public static void main(String[] args) {
            AnimalFactory myAnimalFactory;
            Dog myDog;
            Tiger myTiger;
            System.out.println("***Abstract Factory Pattern Demo*** ");
            //Making a wild dog through WildAnimalFactory
            myAnimalFactory = new WildAnimalFactory();
            myDog = myAnimalFactory.createDog();
            myDog.speak();
            myDog.preferredAction();
            //Making a wild tiger through WildAnimalFactory
            myTiger = myAnimalFactory.createTiger();
            myTiger.speak();
            myTiger.preferredAction();
            System.out.println("******************");
            //Making a pet dog through PetAnimalFactory
            myAnimalFactory = new PetAnimalFactory();
            myDog = myAnimalFactory.createDog();
            myDog.speak();
            myDog.preferredAction();
            //Making a pet tiger through PetAnimalFactory
            myTiger = myAnimalFactory.createTiger();
            myTiger.speak();
            myTiger.preferredAction();
      }
}

Output

Here’s the output.
***Abstract Factory Pattern Demo***
Wild Dog says loudly: Bow-Wow.
Wild Dogs prefer to roam freely in jungles.
Wild Tiger says loudly: Halum.
Wild Tigers prefer hunting in jungles.
******************
Pet Dog says softly: Bow-Wow.
Pet Dogs prefer to stay at home.
Pet Tiger says softly: Halum.
Pet Tigers play in the animal circus.

Q&A Session

  1. 1.

    I am seeing that both the dog and the tiger interfaces contain methods that have the same names (both interfaces contain the speak() and the preferredAction() methods . Is it mandatory?

    No. You can use different names for your methods. Also, the number of methods can be different in these interfaces. But I covered a simple factory pattern and factory method pattern in this book. You may be interested in the similarities or the differences between them. So, I started with an example and keep modifying it. This is why I kept both the speak() and preferredAction() methods in this example. Notice that these methods are used in both the simple factory pattern (see Chapter 24) and the factory method pattern (see Chapter 4).

     
  2. 2.
    What are the challenges of using an abstract factory like this?
    • Any change in the abstract factory forces us to propagate the modification of the concrete factories. If you follow the design philosophy that says program to an interface, not to an implementation, you need to prepare for this. This is one of the key principles that developers always keep in mind. In most scenarios, developers do not want to change their abstract factories.

    • The overall architecture may look complex. Also, debugging becomes tricky in some scenarios.

     
  3. 3.

    How can you distinguish a simple factory pattern from a factory method pattern or an abstract factory pattern?

    I discussed the differences between a simple factory pattern and factory method pattern in the “Q&A Session” section of Chapter 4.

    Let’s revise all three factories with the following diagrams.

     

Simple Factory Pattern Code Snippet

Here’s the code snippet.
Animal preferredType=null;
SimpleFactory simpleFactory = new SimpleFactory();
// The code that will vary based on users preference.
preferredType = simpleFactory.createAnimal();
Figure 5-4 shows how to get animal objects in the Simple Factory pattern.
../images/395506_2_En_5_Chapter/395506_2_En_5_Fig4_HTML.jpg
Figure 5-4

Simple factory pattern

Factory Method Pattern Code Snippet

Here’s the code snippet.
// Creating a Tiger Factory
AnimalFactory tigerFactory =new TigerFactory();
// Creating a tiger using the Factory Method
Animal aTiger = tigerFactory.createAnimal();
//...Some code in between...
// Creating a DogFactory
AnimalFactory dogFactory = new DogFactory();
// Creating a dog using the Factory Method
Animal aDog = dogFactory.createAnimal();
Figure 5-5 shows how to get animal objects in the factory method pattern.
../images/395506_2_En_5_Chapter/395506_2_En_5_Fig5_HTML.jpg
Figure 5-5

Factory method pattern

Abstract Factory Pattern Code Snippet

Here’s the code snippet.
AnimalFactory myAnimalFactory;
Dog myDog;
Tiger myTiger;
System.out.println("***Abstract Factory Pattern Demo*** ");
//Making a wild dog through WildAnimalFactory
myAnimalFactory = new WildAnimalFactory();
myDog = myAnimalFactory.createDog();
//Making a wild tiger through WildAnimalFactory
myTiger = myAnimalFactory.createTiger();
//Making a pet dog through PetAnimalFactory
myAnimalFactory = new PetAnimalFactory();
myDog = myAnimalFactory.createDog();
//Making a pet tiger through PetAnimalFactory
myTiger = myAnimalFactory.createTiger();
myTiger.speak();
myTiger.preferredAction();
Figure 5-6 shows how to get animal objects in the abstract factory method pattern.
../images/395506_2_En_5_Chapter/395506_2_En_5_Fig6_HTML.jpg
Figure 5-6

Abstract factory method pattern

Conclusion

With simple factory, you can separate the code that varies from the rest of the code (basically, you decouple the client codes). This approach helps you easily manage your code. Another key advantage of this approach is that the client is unaware of how the objects are created. So, it promotes both security and abstraction. But it can violate the open-close principle.

You can overcome this drawback using the factory method pattern that allows subclasses to decide how the instantiation process is completed. In other words, you delegate the objects creation to the subclasses that implement the factory method to create objects.

The abstract factory is basically a factory of factories. It creates the family of related objects but it does not depend on the concrete classes.

I tried to maintain simple examples that were close to each other. The factory method promotes inheritance; their subclasses need to implement the factory method to create objects. The abstract factory pattern promotes object composition, where you compose classes using the concrete instances of an abstract factory.

Each of these factories promote loose coupling by reducing the dependencies on concrete classes.
  1. 4.

    In all of these factory examples, you avoid the use of parameterized constructors. Was this intentional?

    In many applications, you see the use of parameterised constructors; many experts prefer this approach. But my focus is purely on design, and so, I ignored the use of parameterised constructors. But if you are a fan of parameterized constructors, let’s modify the implementation slightly so that you can do the same for the remaining parts.

     

Modified Illustration

Let’s assume that you want your factories to initialize tigers with specified colors, and the client can choose these colors.

Let’s modify the following pieces of code (changes are shown in bold).

Modified Implementation

Here’s the modified implementation.
package jdp2e.abstractfactory.questions_answers;
interface Dog
{
      void speak();
      void preferredAction();
}
interface Tiger
{
      void speak();
      void preferredAction();
}
//Types of Dogs-wild dogs and pet dogs
class WildDog implements Dog
{
      @Override
      public void speak()
      {
            System.out.println("Wild Dog says loudly: Bow-Wow.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Wild Dogs prefer to roam freely in jungles. ");
      }
}
class PetDog implements Dog
{
      @Override
      public void speak()
      {
            System.out.println("Pet Dog says softly: Bow-Wow.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Pet Dogs prefer to stay at home. ");
      }
}
//Types of Tigers-wild tigers and pet tigers
class WildTiger implements Tiger
{
      public WildTiger(String color)
      {
            System.out.println("A wild tiger with "+ color+ " is created.");
      }
      @Override
      public void speak()
      {
            System.out.println("Wild Tiger says loudly: Halum.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Wild Tigers prefer hunting in jungles. ");
      }
}
class PetTiger implements Tiger
{
      public PetTiger(String color)
      {
            System.out.println("A pet tiger with "+ color+ " is created.");
      }
      @Override
      public void speak()
      {
            System.out.println("Pet Tiger says softly: Halum.");
      }
      @Override
      public void preferredAction()
      {
            System.out.println("Pet Tigers play in the animal circus. ");
      }
}
//Abstract Factory
interface AnimalFactory
{
      Dog createDog();
      Tiger createTiger(String color);
}
//Concrete Factory-Wild Animal Factory
class WildAnimalFactory implements AnimalFactory
{
      @Override
      public Dog createDog()
      {
            return new WildDog();
      }
      @Override
      public Tiger createTiger(String color)
      {
            return new WildTiger(color);
      }
}
//Concrete Factory-Pet Animal Factory
class PetAnimalFactory implements AnimalFactory
{
      @Override
      public Dog createDog()
      {
            return new PetDog();
      }
      @Override
      public Tiger createTiger(String color)
      {
            return new PetTiger(color);
      }
}
//Client
class AbstractFactoryPatternModifiedExample {
          public static void main(String[] args) {
            AnimalFactory myAnimalFactory;
            Dog myDog;
            Tiger myTiger;
            System.out.println("***Abstract Factory Pattern Demo*** ");
            //Making a wild dog through WildAnimalFactory
            myAnimalFactory = new WildAnimalFactory();
            myDog = myAnimalFactory.createDog();
            myDog.speak();
            myDog.preferredAction();
            //Making a wild tiger through WildAnimalFactory
            //myTiger = myAnimalFactory.createTiger();
            myTiger = myAnimalFactory.createTiger("white and black stripes");
            myTiger.speak();
            myTiger.preferredAction();
            System.out.println("******************");
            //Making a pet dog through PetAnimalFactory
            myAnimalFactory = new PetAnimalFactory();
            myDog = myAnimalFactory.createDog();
            myDog.speak();
            myDog.preferredAction();
            //Making a pet tiger through PetAnimalFactory
            myTiger = myAnimalFactory.createTiger("golden and cinnamon stripes");
            myTiger.speak();
            myTiger.preferredAction();
      }
}

Modified Output

Here’s the modified output.
***Abstract Factory Pattern Demo***
Wild Dog says loudly: Bow-Wow.
Wild Dogs prefer to roam freely in jungles.
A wild tiger with white and black stripes is created.
Wild Tiger says loudly: Halum.
Wild Tigers prefer hunting in jungles.
******************
Pet Dog says softly: Bow-Wow.
Pet Dogs prefer to stay at home.
A pet tiger with golden and cinnamon stripes is created.
Pet Tiger says softly: Halum.
Pet Tigers play in the animal circus.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.235.8