Living in the Tech Avalanche Generation

A practitioners introspective on technology
Archive for November 5th, 2008

GOF Series: Episode #4 [The Builder Pattern] - In IronRuby

So first up let me say that the balance of this series of posts on patterns will be presented using either C# or IronRuby as languages to express the GOF patterns. Why IronRuby you ask? I have taken to learning IronRuby and Silverlight as deeply as possible this year and decided to spice things up for myself by incorporating it in this series of posts. Never fear I will continue to demonstrate most of the remaining patterns in C# but will from time to time present the patterns in both languages. For now however it’s the Builder Pattern exclusively in IronRuby for the dynamic language enthusiasts.

IronRuby is a dynamically typed, object oriented language and runs in the Dynamic Language Runtime. We will demonstrate the builder pattern using IronRuby, Windows Forms and the Ruby In Steel plugin for Visual Studio.Net 2008.

The goal of the Builder Pattern is to separate or abstract away the construction of an object and to allow the same / common construction process to create the object regardless of its representation. The different representations of the object being constructed are created by concrete builders, specifically designed to create one and only one representation of the product class.

The players in the story:

  • The Director

    • Responsible for constructing the Product object via an interface (mixin in the case of this example using IronRuby) implemented by a concrete builder.
  • The Builder

    • Provides the interface (object in this case) that creates the Product(s) constituent parts and is implemented (included as a mixin with IronRuby) by concrete builders.
  • The Concrete Builder

    • Builds the constituent parts of the Product object.
  • The Product

    • The object whose parts are created by the concrete builder.

BuilderPattern

In C# or other statically typed languages such as java, the builder pattern relies on an abstract class design and inheritance. In IronRuby there is no concept of an interface therefore a different approach is required. We can use a mixin to provide the common behavioural aspects and use arguments to diverge the different concrete builders. The construction of the ‘Product’ is abstracted from the ‘Director’ by the ‘Builder’ and it’s Concrete implementations. To obtain different representations of the Product object new concrete builder objects are created. The Builder Pattern creates it’s Product object in parts via the Director and Builders abstract signatures, however an alternate approach with IronRuby is to substitute the abstract class for a mixin.

#Product
class FootballTeam

    def team_id?()
        self.hash
    end

    def team_type_name?()
        @team_type_name
    end

    def team_properties?()
        @team_properties
    end

    def initialize(name)
        @team_type_name = name
        @team_properties = Hash.new(“Staff Role does not exist!”)
    end

end

#Builder
module FootballTeamBuilder

    attr_reader :name
    attr_writer :name

    def footy_team?()
        @footy_team
    end

    def build_init()
        @footy_team = FootballTeam.new(name)
    end

    def build_players(number_of_players)
        @footy_team.team_properties?["Players"] = number_of_players
    end

    def build_ball_shape(shape_of_ball)
        @footy_team.team_properties?["ballshape"] = shape_of_ball
    end

    def build_games_per_season(number_of_games)
        @footy_team.team_properties?["games"] = number_of_games
    end

    def print_team_details()

        attributes =  “****************************” +
            “******************************\r\n”

        attributes += “Created a #{name} team with the “ +
            “following attributes :\r\n”

        @footy_team.team_properties?.each { |k,v|
            attributes += k.to_s + ” “ + v.to_s + “\r\n” }

        attributes += “\n***************************” +
            “*******************************\n”

        return attributes
    end

end

#Concrete Builder”
class AustralianRulesFootballTeamBuilder 

    include FootballTeamBuilder

    def build_all()
        self.name = “Aussie Rules”
        build_init()
        build_ball_shape(“Oval”)
        build_games_per_season(22)
        build_players(18)
    end

end

#Concrete Builder
class RugbyLeagueFootballTeamBuilder

    include FootballTeamBuilder

   def build_all()
        self.name = “Rugby League”
        build_init()
        build_ball_shape(“Oval”)
        build_games_per_season(24)
        build_players(13)
    end

end

#Concrete Builder
class SoccerFootballTeamBuilder

    include FootballTeamBuilder

    def build_all()
        self.name = “Soccer”
        build_init()
        build_ball_shape(“Round”)
        build_games_per_season(44)
        build_players(11)
    end

end

#Director Class
class GoverningBody

    def build_football_team(football_team_builder)
        unless football_team_builder.is_a?(FootballTeamBuilder)
            fail NoNewMethodError.new(“Cannot build with arguments that are “ +
                “not FootballTeamBuilder class objects”)
        end
        football_team_builder.build_all
    end

end
 
Here’s our form and its form load event method.
 
def Form1_Load(sender, e)

      #new up a Director
      f = GoverningBody.new

      #new up a concrete builder
      soccer_builder = SoccerFootballTeamBuilder.new

      #go again a second time with another builder
      aussie_rules_builder = AustralianRulesFootballTeamBuilder.new

      #go again a second time with another builder
      rugby_league_builder = RugbyLeagueFootballTeamBuilder.new

      #pass the bulders build to the Director
      f.build_football_team(soccer_builder)
      f.build_football_team(aussie_rules_builder)
      f.build_football_team(rugby_league_builder)

      #store the teams and details in arrays
      @team1 = [soccer_builder.footy_team?.team_type_name?,
        soccer_builder.print_team_details]
      @team2 = [aussie_rules_builder.footy_team?.team_type_name?,
        aussie_rules_builder.print_team_details]
      @team3 = [rugby_league_builder.footy_team?.team_type_name?,
        rugby_league_builder.print_team_details]

      self.listBox1.Items.Add(@team1[0])
      self.listBox1.Items.Add(@team2[0])
      self.listBox1.Items.Add(@team3[0])

end
ironruby_builder_ui
ironruby_builder_ide Used in concert with a Windows::Forms application (with some help from Ruby In Steel) we can build the following user interface to demonstrate our Builder(s) in action. The entire code can be found here and includes all the code and presentations from previous episodes in the series. Next in the series is the last of the creational patterns, the Prototype pattern.

Share/Save/Bookmark

2 comments