Skip to content

Instantly share code, notes, and snippets.

@kchens
Created March 25, 2015 23:44
Show Gist options
  • Save kchens/c190e745ab14ef29598d to your computer and use it in GitHub Desktop.
Save kchens/c190e745ab14ef29598d to your computer and use it in GitHub Desktop.
POODR: Chapter 5 - Reducing Costs With Duck Typing
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Overlooking Ducks
# 1 -------------------BAD
class Trip
attr_reader :bicycles, :customers, :vehicle
def prepare(mechanic)
# no depedency on mecahnic
# create a dependency that the object must respond to #prepare_bicycles
mechanic.prepare_bicycles(bicycles)
end
# ...
end
class Mechanic
def prepare_bicycles(bicycles)
bicycles.each { |bicycle| prepare_bicycle(bicycle) }
end
def prepare_bicycle(bicycle)
# ...
end
end
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Compounding The Problem
# 2 -------------------WORST
class Trip
attr_reader :bicycles, :customers, :vehicle
def prepare(preparers)
# Method now needs to check each object for its class
# In scaling an app, this case statement grows
preparers.each do | preparer |
case preparer
when Mechanic
preparer.prepare_bicycles(bicycle)
when TripCoordinator
prepare.buy_food(customers)
when Driver
prepare.gas_up(vehicle)
prepare.fill_water_tank(vehicle)
end
end
end
end
class TripCoordinator
def buy_food(customers)
# ...
end
end
class Driver
def gas_up(vehicle)
# ...
end
def fill_water_tank(vehicle)
# ...
end
end
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Finding the Duck
# 3 -------------------BEST
class Trip
attr_reader :bicycles, :customers, :vehicle
# prepare ultimately has a single purpose, its arguments arrive wishing to
# collaborate to accomplish a single goal.
def prepare(preparers)
# passes self as a parameter
preparers.each { |preparer| preparer.prepare_trip(self) }
end
end
class Mechanic
def prepare_trip(trip)
trip.bicycles.each { |bicycle| prepare_bicycle(bicycle) }
end
# ...
end
class TripCoordinator
def prepare_trip(trip)
buy_food(trip.customers)
end
# ...
end
class Driver
def prepare_trip(trip)
vehicle = trip.vehicle
gas_up(vehicle)
fill_water_tank(vehicle)
end
# ...
end
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Recognizing Hidden Ducks
# 4 -------------------BAD
# A. CASE STATEMENTS (SEE ABOVE)
# B. #kind_of? and #is_a?
def prepare(preparer)
if preparer.kind_of?(Mechanic)
preparer.prepare_bicycles(bicycle)
elsif preparer.kind_of?(TripCoordinator)
preparer.buy_food(customers)
elsif preparer.kind_of?(Driver)
preparer.gas_up(vehicle)
preparer.fill_water_tank(vehicle)
end
end
# C. #responds_to?
def prepare(preparer)
if preparer.respond_to?(:prepare_bicycles)
preparer.prepare_bicycles(bicycle)
elsif preparer.respond_to?(:buy_food)
preparer.buy_food(customers)
elsif preparer.respond_to?(:gas_up)
preparer.gas_up(vehicle)
preparer.fill_water_tank(vehicle)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment