-
-
Save sgharms/3834658 to your computer and use it in GitHub Desktop.
class Kitchen | |
def prepare_hamburger | |
return ( %w/ artisinal_bun niman_ranch_beef cowgirl_creamery_bleu_cheese lettuce central_valley_avocado/. | |
join ', ' ) + " hamburger." | |
end | |
def generate_mixin | |
Module.new do | |
def prepare_hamburger | |
puts "Enjoy a: " + @kitchen.prepare_hamburger | |
end | |
end | |
end | |
end | |
class Restaurant | |
def initialize(name) | |
@name = name | |
@kitchen = Kitchen.new | |
self.extend @kitchen.generate_mixin | |
end | |
end | |
my_resto = Restaurant.new "The Stinky Cow" | |
my_resto.prepare_hamburger |
#!/usr/bin/env ruby | |
# | |
# The Goal: Use composition effectively. A Restaurant purports to "prepare a hamburger," but we | |
# know that it is actually the responsibility of the kitchen to do the work. | |
# | |
# Key feature: the token used for the action is the SAME between the two entitites `prepare_hamburger`. | |
# | |
# Desired: A way to have Restaurant delegate :prepare_hamburger to Kitchen **AND** | |
# **do not** define the wrapper :prepare_hamburger on Restaurant. | |
class Kitchen | |
def prepare_hamburger | |
return ( %w/ artisinal_bun niman_ranch_beef cowgirl_creamery_bleu_cheese lettuce central_valley_avocado/. | |
join ', ' ) + " hamburger." | |
end | |
end | |
class Restaurant | |
def initialize(name) | |
@name = name | |
@kitchen = Kitchen.new | |
end | |
def prepare_hamburger | |
puts "Enjoy a: " + @kitchen.prepare_hamburger | |
end | |
end | |
my_resto = Restaurant.new "The Stinky Cow" | |
my_resto.prepare_hamburger |
class Kitchen
def prepare_hamburger
return ( %w/ artisinal_bun niman_ranch_beef cowgirl_creamery_bleu_cheese lettuce central_valley_avocado/.
join ', ' ) + " hamburger."
end
def generate_mixin
Module.new do
def prepare_hamburger
puts "Enjoy a: " + @kitchen.prepare_hamburger
end
end
end
end
class Restaurant
def initialize(name)
@name = name
@kitchen = Kitchen.new
self.extend @kitchen.generate_mixin
end
end
my_resto = Restaurant.new "The Stinky Cow"
my_resto.prepare_hamburger
The first is simple and plain. It feels like needless work to write those generator methods.
The second feels a bit more like Ruby Metaprogramming style, but the down side is that the Kitchen
class has to know that it was instantiated on the @kitchen
iVar. That doesn't seem right.
I'm looking for a better implementation.
How the hell do you delete a gist comment (see 2 up).
I think it's hard for me to make suggestions about this code, because I'm not totally sure I understand the point. I think I need something a little less abstract. For example, Kitchen is an object with no state, so why not just make it a module?
I don't like the mix-in trick. It seems like a lot of magic for a gain I don't really understand.
I see about one change I am certain sure I would make for this code:
class Kitchen
INGREDIENTS = %w[ artisinal_bun
niman_ranch_beef
cowgirl_creamery_bleu_cheese
lettuce
central_valley_avocado ]
def prepare_hamburger
"#{INGREDIENTS.join(', ')} hamburger."
end
end
class Restaurant
def initialize(name, kitchen = Kitchen) # the important change!
@name = name
@kitchen = kitchen.new
end
def prepare_hamburger
puts "Enjoy a: " + @kitchen.prepare_hamburger
end
end
my_resto = Restaurant.new("The Stinky Cow")
my_resto.prepare_hamburger
To me, this is key because it lets me test Restaurant's delegation, wrap Kitchen before I pass it in, or out and out replace it with a similar interface. That feels like all I need here.
Perhaps I didn't understand the question well enough though.
If your goal is to use composition effectively, and then you call #extend
, you've failed, because mixins are inheritance, not composition. ;)
That said, I sorta agree with James; I'm also not sure what the point is... :/
Yay Ruby!!