Abstract Factory Design Pattern Example

Abstract Factory Design Pattern: Provide an interface for creating families of related or dependent objects without specifying their concrete classes -- By THE GOF BOOK.


The abstract factory pattern is an extension of the  Factory Method pattern. Both are about creating the new objects, while abstract factory cares more about a family of objects or products to be produced.

In simple words, A normal factory is used to create sets of related or similar objects and an abstract factory is used to return instance of factories. Thus, we can say, an abstract factory is used to return instance of factories that can be used to create similar or related objects. A factory of factories.

As there is a ‘abstract’ word in the pattern name don’t mistake and confuse it with java ‘abstract’ keyword. It is not related to that. This abstract is for abstraction from object oriented programming point of view.

Lets understand this with a simple example.
Problem: As in my previous post  Factory Method pattern, we created a media player and a decoder factory to decode the given media file before playing. If we see the code of decoder factory we will notice that there is a problem with the code, as audio and video decoders are mixed in the DecoderFactory.java.
Solution: To avoid such problems we need to separate the audio and video decoders, means we can have separate factories for audio decoders family and video decoders family.
To do this we need to make use of Abstract factory pattern as following.
Plz refer the previous post for Factory Design Pattern to see how to implement audio PM3 and video MP4 Decoders. A simple ACC audio decoder may look like blow code snippet.


public class ACCDecoder implements Decoder {
  @Override
  public InputStream decodeFile(String mediaFileName) {
  //decode your file here and return the decoded stream
  System.out.println("ACCDecoder: decoding file "+mediaFileName);
return null;
  }
}


Lets modify our DecoderFactory as an interface and let the Audio and Video decoder factories classes to implement this to produce the audio and video decoder objects on request.
DecoderFactory.java


public interface DecoderFactory {
            Decoder getDecoder(String type);
}


Let AudioDecoderFactory.java implement this interface to produce decoder from audio decoders family.

public class AudioDecoderFactory implements DecoderFactory{
           @Override
           public Decoder getDecoder(String type) {
                type = type.toUpperCase();
                if (type.endsWith("MP3")) {
                        return new MP3Decoder();
                } else if (type.endsWith("ACC")) {
                        return new ACCDecoder();
                }
                return null;
         }
}


Let VideoDecoderFactory.java implement this interface  to produce decoder from video decoders family

public class VideoDecoderFactory implements DecoderFactory {
  @Override
  public Decoder getDecoder(String type) {
  type = type.toUpperCase();
  if (type.endsWith("MP4")) {
  return new MP4Decoder();
  } else if (type.endsWith("FLV")) {
return new FLVDecoder();
  }
  return null;
  }
}


Now we will create an AbstractFactory.java class which will give us a audio or video factory instance on request.

public class AbstractFactory {
  public static DecoderFactory getDecoderFactory(String type) {
  if ("audio".equalsIgnoreCase(type)) {
  return new AudioDecoderFactory();
  } else if ("video".equalsIgnoreCase(type)) {
  return new VideoDecoderFactory();
  }
  throw new RuntimeException(type+ " not supported");
  }
}

Now its time to test our abstract factory class, so like media player in previous post of factory pattern we need a client to use our abstract factory. A simple client can be written as following.

public class AbstractFactoryClient {
  public static void main(String[] args) {
  // get Audio factory to produce audio decoders.
  DecoderFactory decoderFactory = AbstractFactory.getDecoderFactory("audio");
  Decoder decoder = decoderFactory.getDecoder("MP3");
  decoder.decodeFile("song.mp3");
   
  // get Video factory to produce video decoders
  decoderFactory = AbstractFactory.getDecoderFactory("video");
  decoder = decoderFactory.getDecoder("MP4");
  decoder.decodeFile("videoSong.mp4");
  }
}


Output:

MP3Decoder: decoding file song.mp3
MP4Decoder: decoding file videoSong.mp4

Here we can see how the abstract factory pattern helps us to separate audio and video decoder objects creation, by using audio and video factories. This way AudioFactory will produce only audio decoders and VideoFactory will produce only video decoders by doing so our design will be very nice and clean. So to add a new audio and video decoder support we need to just update the related Factory class with few lines of simple code.

No comments :

Post a Comment