A factory produces something. Accordingly the Factory pattern describes, how objects are produced.
First of all the exemplary initial situation. A product class for objects having a name and a price:
class Product
attr_accessor :name, :price
def initialize name, price
@name = name
@price = price
end
end
In addition there are several pricing policies, represented by the following classes:
module PricingPolicy
class Fixed
attr_accessor :product
def initialize product
@product = product
end
def price
product.price.to_f
end
end
end
There is a fixed price Fixed.
module PricingPolicy
class Flexible < Fixed
FACTOR = 0.8...1.5
def price
(super * rand(FACTOR)).round 2
end
end
class Discount < Fixed
FACTOR = 0.8
def price
(super * 0.8).round 2
end
end
end
Furthermore there is also a flexible pricing (Flexible), at random in the range of 80% to 150% of the fixed price.
And finally there the discount pricing /Discount), which is 80% of the original price.
The pricing policies have to be applied to the products. Adopting the Factory pattern is reasonable, especially due to moving the responsibility for instantiating the objects to a dedicated pivotal place.
In Ruby there are several approaches, how to implement the Factory. But the following one is quite common:
module PricingPolicy
POLICIES = {
'flexible' => Flexible,
'prestige' => Prestige
}
private_constant :POLICIES
def self.for name, product=nil
(POLICIES[name.to_s.downcase] || Fixed).new product
end
end
Basically the Factory contains a Hash for all concerned object classes. In the case the corresponding class class can not be found, there is a default class (Fixed) defined.
Object generating methods often are named for or build, because new suggests an object of that class would be provided. That is not the case for a Factory. It produces objects of other classes:
book = Product.new 'Design Patterns In Ruby', 50
# => #<Product:0x000000038873d8 ... >
policy = PricingPolicy.for :discount, book
=> #<PricingPolicy::Discount:0x000000038445b0 ... >
policy.price # => 40.0
PricingPolicy.for(:flexible, book).price # => 52.02
PricingPolicy.for(:fixed, book).price # => 50.0