The Factory Method

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.

Cheers,

Enrique Comba R.

On 5/10/07, Enrique Comba R. [email protected] wrote:

class Product

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

Hey Pat!

On 10 May 2007, at 09:16, Pat M. wrote:

class AmericanCoffeeShop

module CoffeeProvider
def make_coffee
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

Thanks a lot for the input!

Do you mind if I post your answer in Ruby Patterns? http://
www.rubypatterns.org

On 10 May 2007, at 09:30, Pat M. wrote:

methods with the same method names and signatures.
end
whatever kind it wants.
def order
Coffee.new :ingredients => [ :water, :mud ]

Thanks a lot for the input!

Do you mind if I post your answer in Ruby Patterns? http://
www.rubypatterns.org

Go for it.

Done :wink: http://www.rubypatterns.org/doku.php/
gang_of_four_patterns:factory_method

On May 10, 2007, at 1:56 AM, Enrique Comba R. wrote:

I was thinking about the Factory Method Pattern and following came
to my mind.

In addition to Pat’s great answer, I think it’s important to note
that classes are objects in Ruby. This often aids in Factory pattern
scenarios. For example:

class Prose
def initialize(title, author)
@title = title
@author = author
end
def inspect
“#{self.class}: #{@title} by #{@author}”
end
end
=> nil

class Novel < Prose; end
=> nil

class ShortStory < Prose; end
=> nil

class Author
def initialize(name)
@name = name
end
def to_s
@name
end
def write(type, title)
type.new(title, self)
end
end
=> nil

james = Author.new(“James”)
=> #<Author:0x14a11d0 @name=“James”>

james.write(Novel, “Ruby: The Girl I Loved”)
=> Novel: Ruby: The Girl I Loved by James

james.write(ShortStory, “Little Ruby Riding Hood”)
=> ShortStory: Little Ruby Riding Hood by James

Just some more food for thought.

James Edward G. II

On 10 May 2007, at 14:33, James Edward G. II wrote:

def initialize(title, author)
class ShortStory < Prose; end
end

James Edward G. II

Thanks a lot James, I think this clarifies (at least from the newbie
point of view) a lot of the power under the hood in Ruby!

I’m now thinking where to include this in the Wiki.

Any idea?

Cheers, and thanks again!

On 5/10/07, Enrique Comba R. [email protected] wrote:

I’m sure they discusss it in DP, but you don’t need to implement this
def make_coffee

CoffeeProvider.

Go for it.

Pst

On 10 May 2007, at 15:14, James Edward G. II wrote:

I feel it could be part of a discussion of the factory pattern. It
fits well there, I think.

James Edward G. II

Yep! Included! http://www.rubypatterns.org/doku.php/
gang_of_four_patterns:factory_method

By the way, feel free to edit the wiki in your liking. I actually set
it up as a collaborative project where we all can share our knowledge
in the Design Pattern implementation and discoveries in Ruby :wink:

Cheers!

Enrique Comba R.

Enrique,

This is a good idea. As I’m currenlty looking at patterns with regards
to Perl and Ruby … this will whet my appetite more.

-Ants

Enrique Comba R. [email protected] wrote:
On 10 May 2007, at 15:14, James Edward G. II wrote:

I feel it could be part of a discussion of the factory pattern. It
fits well there, I think.

James Edward G. II

Yep! Included! http://www.rubypatterns.org/doku.php/
gang_of_four_patterns:factory_method

By the way, feel free to edit the wiki in your liking. I actually set
it up as a collaborative project where we all can share our knowledge
in the Design Pattern implementation and discoveries in Ruby :wink:

Cheers!

Enrique Comba R.

On 10 May 2007, at 16:04, Anthony G. wrote:

Enrique,

This is a good idea. As I’m currenlty looking at patterns with
regards to Perl and Ruby … this will whet my appetite more.

-Ants

You are free to add your findings in the Wiki Ants! I will take care
of the formating if there is need… I appreciate any input!

Cheers,

Enrique Comba R.

errrm, just had a look at the cofee factory, and haven;t you actually
missed off the factory part?

Enrique Comba R. [email protected] wrote:
On 10 May 2007, at 16:04, Anthony G. wrote:

Enrique,

This is a good idea. As I’m currenlty looking at patterns with
regards to Perl and Ruby … this will whet my appetite more.

-Ants

You are free to add your findings in the Wiki Ants! I will take care
of the formating if there is need… I appreciate any input!

Cheers,

Enrique Comba R.

On May 10, 2007, at 8:10 AM, Enrique Comba R. wrote:

Thanks a lot James, I think this clarifies (at least from the
newbie point of view) a lot of the power under the hood in Ruby!

Sure.

I’m now thinking where to include this in the Wiki.

Any idea?

I feel it could be part of a discussion of the factory pattern. It
fits well there, I think.

James Edward G. II

On 10.05.2007 15:25, Enrique Comba R. wrote:

I’m now thinking where to include this in the Wiki.
http://www.rubypatterns.org/doku.php/gang_of_four_patterns:factory_method

By the way, feel free to edit the wiki in your liking. I actually set it
up as a collaborative project where we all can share our knowledge in
the Design Pattern implementation and discoveries in Ruby :wink:

I’d go even further and point out that every class[1] in Ruby is a
concrete factory - maybe even at the start of the article. In the most
general way the interface is new() i.e. what you would call a “default
constructor” in other languages. Few know that classes usually also
provide method #allocate to create an instance of the class but without
invoking #initialize. So that would be the second factory method that
all classes support. :slight_smile:

Also, you can create any number of additional factory methods on a
class, if you wish so.

And finally, since there are no interfaces in Ruby the pattern might be
less obvious, even if implemented “properly”, i.e. with concrete
creation methods. (I think you do mention that on the Wiki already.)

Kind regards

robert

[1] excluding classes that do not support #new.

Thank you so much for this discussion, and for starting the wiki.

I picked up “Head First Design Patterns” a while back to try to learn
design patterns. The book is completely Java-oriented, but I thought I
could use my knowledge of Ruby to “translate” the lessons in the book (I
don’t have any Java experience). By an unfortunate coincidence, though,
the first pattern they covered was the Factory pattern, and based on my
Ruby experience, not only couldn’t I figure out how to do it in Ruby, I
couldn’t even understand what problem they were trying to solve! I put
it down for a while and moved on to other computer books. Now that this
wiki is up and running, though, I do believe I’ll go back and tackle it
again!

On 10 May 2007, at 17:00, Robert K. wrote:

[1] excluding classes that do not support #new.
Thanks for the clarification Robert! I included it actually in the
Wiki as I think it’ll help to further understand this concepts in
Ruby…

On 10 May 2007, at 18:10, Chris G. wrote:

Ruby experience, not only couldn’t I figure out how to do it in

Hey Chris!

Thanks a lot! You are welcome to post your findings in the Wiki and
help to improve the body of knowledge even more there. I think it is
a great thing to do and I am happy that it might help some of us…

Cheers,

Enrique Comba R.