HiveBrain v1.2.0
Get Started
← Back to all entries
principlerubyMinor

Is this an appropriate class design for the strategy pattern in Ruby?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thisthedesignrubyappropriateforstrategyclasspattern

Problem

I am fairly satisfied with my solution here but I would definitely appreciate any constructive criticism of my style and design. The basic idea is to use the strategy pattern to simplify assembling a custom procedural generator. I'm using modules rather than classes for improved simplicity of 'mixing' everything together.

Here's the root of the 'strategy' class tree, AbstractStrategy:

#
      #    the contract here is that the child strategy should implement an apply
      #    function which takes a target problem instance and hash options.
      #
      module AbstractStrategy
        def apply!(problem, opts={})
          log.debug "--- AbstractStrategy.apply! problem=#{problem}, opts=#{opts}"
          apply(problem, opts)  
        end
      end


One level down, we have another 'parent' pattern which implements a particular strategy 'action' or 'style'. In this case it's an AbstractGenerationStrategy which implements apply according to the contract above.

#
      # the contract here is that the child strategy needs to implement "generate_[component]!({})"
      #
      module AbstractGenerationStrategy extend AbstractStrategy
        include AbstractStrategy

        def extend!(base)
          log.debug("--- extending #{base}")
          self.extend(base)
        end

        #
        # => use like -- generate :rooms, ConstructNestedRoomsStrategy, ...opts...
        #
        def generate(component, strategy, opts={})
          log.debug "--- AbstractGenerationStrategy.generate[component=#{component}, strategy=#{strategy}]"
          extend!(strategy)
          apply!(component,opts)
        end

        def apply(component_to_generate, opts)
          log.debug "--- AbstractGenerationStrategy.apply component=#{component_to_generate}, opts=#{opts})"
          self.send("generate_#{component_to_generate}!", opts)
        end
      end


To see this in action, one strategy module which implements the above contract is `AbstractRoomGener

Solution

Stop trying to write Ruby like Java. You've got a whole mess of modules to do something fairly simple.

Most (not all) of the Gang of Four patterns are workarounds for lack of flexibility in languages like C++ and Java, and are less necessary in a language like Ruby that has classes that are first-class objects and always extensible.

I'd like to know a bit more about your use case, but it seems to me that you can probably remove a layer or two of indirection.

Context

StackExchange Code Review Q#4930, answer score: 3

Revisions (0)

No revisions yet.