The Artima Developer Community
Sponsored Link

Ruby Code & Style
Modular Architectures with Ruby
by Jack Herrington
October 10, 2005

<<  Page 2 of 4  >>

Advertisement

Factoring to Factories

The next step is to refactor the code to use the Factory pattern. In that pattern each parser will have two classes. The first is the parser itself, and the second is a factory that creates parsers of that type. Why factories? Because the code should be able to get the types of feeds the parser can handle without creating a parser.

The newly refactored code looks like this:

class ParserFactory
  def get_type()
    return ""
  end
  def create()
    return nil
  end

  @@factories = []

  def ParserFactory.add_factory( p )
    @@factories.push( p )
  end

  def ParserFactory.factories()
    return @@factories
  end

  def ParserFactory.parser_for( type )
    @@factories.each { |pfc|
      pf = pfc.new()
      if pf.get_type() == type 
        return pf.create()
      end
    }
    return nil
  end
end

class Parser
  def parse( xml )
    return nil
  end
end

class RSSParser < Parser
  def parse( xml )
    # Parse the XML up and return some known format
    return nil
  end
end

class RSSFactory < ParserFactory
  def get_type()
    return "RSS"
  end
  def create()
    return RSSParser.new()
  end
end

ParserFactory.add_factory( RSSFactory )

class RDFParser < Parser
  def parse( xml )
    # Parse the XML up and return some known format
    return nil
  end
end

class RDFFactory < ParserFactory
  def get_type()
    return "RDF"
  end
  def create()
    return RDFParser.new()
  end
end

ParserFactory.add_factory( RDFFactory )

Now the factories register themselves with a factory base class. This class has the helpful parser_for method which returns a parser for a given input type.

The nice thing about this refactoring is that the Parser classes do just what they should, take XML and returns a list of articles.

The test code needs to be changed around a little bit to handle this new factory system:

require "parse_mods.rb"

# Create new factory and instantiate a new parser
af = RSSFactory.new
a = af.create()
print "Building an RSS parser:\n"
p a
print "\n"

# Iterate through all of the available types
print "Available parser types:\n"
ParserFactory.factories.each { |factory_class|
  a = factory_class.new()
  p a.get_type()
}
print "\n"

# Check the new parser_for method
print "Request a parser for RDF:\n"
pf = ParserFactory.parser_for( "RDF" );
p pf

And I run it like this:

% ruby test.rb
Building an RSS parser:
#

Available parser types:
"RSS"
"RDF"

Request a parser for RDF:
#
%

The first part of the code creates the RSS parser directly. The second section walks through all of the available parsers. And the third section selects a parser by name.

The UML for the refactored code looks like Figure 2.

Figure 2: The factories and their related parsers.
Figure 2. The factories and their related parsers

The list of what parsers are available is now in ParserFactory. And each parser has it’s corresponding parser factory which creates it.

<<  Page 2 of 4  >>


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us