Eine Fabrik produziert etwas. Und abgeleitet davon, beschreibt das Factory Entwurfsmuster, wie Objekte produziert werden.
Zunächst einmal eine beispielhafte Ausgangssituation. Eine Produktklasse deren Objekte durch einen Namen und einen Preis gekennzeichnet sind:
class Product
attr_accessor :name, :price
def initialize name, price
@name = name
@price = price
end
end
Außerdem exestieren diverse Preisberechnungsmodelle, abgebildet durch die folgenden Klassen:
module PricingPolicy
class Fixed
attr_accessor :product
def initialize product
@product = product
end
def price
product.price.to_f
end
end
end
Es gibt den festen Preis 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
Außerdem gibt es den flexiblen Preis (Flexible), der zufällig zwischen 80% und 150% des festen Preises schwankt. Und schließlich der Rabattpreis (Discount), der 80% des originalen Preises ausgibt.
Nun sollen die Preismodelle auf die Produkte angewendet werden. Dafür bietet sich das Factory Entwurfsmuster an, zumal damit die Verantwortung der Erstellung der Objekte zentral an einer dedizierten Stelle liegt.
In Ruby gibt es sicherlich verschiedene Ansätze, wie eine Factoy implementiert werden kann. Weit verbreitet ist folgender Ansatz:
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
Im Grunde beinhaltet die Factory einen Hash für die möglichen Objektklassen. Für den Fall, daß keine entsprechende Klasse gefunden werden kann, ist eine Standardklasse definiert (in diesem Fall Fixed).
Für die Objektgenerierende Methode wird oft for oder build verwendet, weil new suggeriert, daß ein Objekt der entsprechenden Klasse erstellt wird. In einer Factory ist das nicht der Fall. Dort werden Objekte anderer Klassen erzeugt:
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