Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a factory know which type of object to create?

I believe the factory method design pattern is appropriate for what I'm trying to do, but I'm not sure how much responsibility (knowledge of subclasses it creates) to give it. The example of using the factory method pattern at Wikipedia describes the situation I'm in almost exactly:

public class ImageReaderFactory 
{
    public static ImageReader getImageReader( InputStream is ) 
    {
        int imageType = figureOutImageType( is );

        switch( imageType ) 
        {
            case ImageReaderFactory.GIF:
                return new GifReader( is );
            case ImageReaderFactory.JPEG:
                return new JpegReader( is );
            // etc.
        }
    }
}

My question is, what does the figureOutImageType function look like? In this specific example, I would assume that it checks a file header in the InputStream to determine which image format the data is in. I would like to know if the ImageReaderFactory itself knows how to parse file headers and determine if the file type is GIF, JPEG, etc, or if it calls a function inside each Reader class that lets it know what type of image it is. Something like this, maybe:

int figureOutImageType(InputStream is)
{
    if(GifReader.isGIF(is))
        return ImageReaderFactory.GIF;
    else if(JpegReader.isJPEG(is))
        return ImageReaderFactory.JPEG;
    // etc.
}

It seems like having the factory know how to parse images breaks encapsulation, and letting the subclasses decide which one should be created is part of the factory method design pattern. Yet, it also seems like the figureOutImageType function is just adding some redundant code, because why not just have each subclass perform its check on the InputStream in the getImageReader function and skip the switch case?

I haven't had any experience using factories before, and I was hoping to get some insight from some people who have used them in the past on the best way to handle this problem. Is it okay to have the factory know about the inner workings of its subclasses, or should they be responsible for letting the factory know which to create, and how do you organize it all?

Thanks!

like image 761
Venesectrix Avatar asked Mar 31 '09 23:03

Venesectrix


2 Answers

Factory should have some idea about choosing the actual object to create. For example, WebRequest.Create method in .NET, should be able to choose between the different protocol clients by checking the protocol part of the Uri. It doesn't need to parse the whole thing. Just the part required to distinguish which class is going to be responsible for it (in your example, it'll probably be just the file header).

Regarding your question about breaking encapsulation, not really... Most of the time, the factory is hardcoded and already knows about different types of classes and their features. It already depends on the functionality offered by a known set of classes, so you are not adding much to it. You can also encapsulate the detection part of the factory in another helper class that can be used both by the factory and the subclasses (in the sprit of DRY principle).

like image 84
mmx Avatar answered Sep 23 '22 02:09

mmx


Both are valid choices depending on context.

IF you're architecting for extensibility - say a plugin model for different ImageReaders - then your Factory class cannot know about all possible ImageReaders. In that case, you go the ImageReader.CanRead(ImageStream) route - asking each implementer until you find one that can read it.

Beware, that sometimes ordering does matter here. You may have a GenericImageReader that can handle JPGs, but a Jpeg2000ImageReader that is better at it. Walking the ImageReader implementers will stop at whichever is first. You may want to look at sorting the list of possible ImageReaders if that's a problem.

Otherwise, if the list of ImageReaders is finite and under your control, then you can go the more traditional Factory approach. In that case, the Factory decides what to create. It's already coupled to the concrete implementations of ImageReader by the ctor, so adding rules for each ImageReader doesn't increase coupling. If the logic to pick a ImageReader is mainly in the ImageReader itself, then to avoid duplication of code, you can still go the ImageReader.CanRead(ImageStream) route - but it could just be hardcoded which types you walk.

like image 38
Mark Brackett Avatar answered Sep 22 '22 02:09

Mark Brackett