From: Pat Maddox Date: 2007-05-10T16:16:58+09:00 Subject: Re: The Factory Method On 5/10/07, Enrique Comba Riepenhausen wrote: > Hi everyone, > > as you know I started a few days ago the Ruby Patterns Wiki and now I > am starting to put in some samples. As you know, although I am not > new to software development, I am still a newbie in Ruby. > > I was thinking about the Factory Method Pattern and following came to > my mind. If we follow the Pattern by the book (GoF) we would have > following code (simplified for the purpose of clarity): > > class Product > def hi > "hello there" > end > end > > class ConcreteProduct < Product > def hi > "Hello from the concrete implementation" > end > end > > class Creator > def create_product > end > end > > class ConcreteCreator < Creator > def create_product > ConcreteProduct.new > end > end > > Obviously this code strikes in Ruby (specially the creator class that > doesn't make much sense to me). How would you people think this could > be implemented in Ruby? Or better to say, what is the Ruby way to > solve this intent of the Factory Method Pattern: Define an interface > for creating an object, but let subclasses decide which class to > instantiate. Factory Method lets a class defer instantiation to > subclasses. One clue is that the example is coded in Java, vs smalltalk. The reason for that is that Smalltalk doesn't really have the problem they're solving here. An "interface" is just going to be a bunch of methods with the same method names and signatures. I'm sure they discusss it in DP, but you don't need to implement this pattern with an abstract class. That's just there because you want common behavior. So how do you implement this pattern in Ruby? class AmericanCoffeeShop def make_coffee Coffee.new :ingredients => [ :water, :mud ] end end class ItalianCoffeeShop def make_coffee Espresso.new end end Simple, you've implemented the factory method pattern. We have an interface - make_coffee - and each class can instantiate an object of whatever kind it wants. If some client code needs to have a coffee made, you can just pass it an instance of either of those classes and it'll run fine. Shared behavior can be provided by a mixin (whereas in Java you need a superclass). module CoffeeProvider def order take_payment give_change make_coffee end end class AmericanCoffeeShop include CoffeeProvider def make_coffee Coffee.new :ingredients => [ :water, :mud ] end end class ItalianCoffeeShop include CoffeeProvider def make_coffee Espresso.new end end Now we've achieved the desired behavior. We've defined the high-level behavior of taking an order, but placed the responsibility on lower-level implementation details in another class. Now anyone can come along and write a class that knows how to provide an order of coffee, all without any foresight from the initial author of CoffeeProvider. Pat