Menu
Coddy logo textTech

Fabrikmuster

Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 43 von 57.

Das Fabrikmuster bündelt die Objekterstellung an einer Stelle. Aufrufer fragen nach dem, was sie benötigen, oft anhand eines Namens, und erhalten ein fertiges Objekt, ohne zu wissen, welche Klasse erstellt wurde:

class Square
  def initialize(side)
    @side = side
  end

  def area
    @side * @side
  end
end

class Circle
  def initialize(r)
    @r = r
  end

  def area
    (3.14159 * @r * @r).round(2)
  end
end

class ShapeFactory
  def self.create(kind, size)
    case kind
    when "square" then Square.new(size)
    when "circle" then Circle.new(size)
    end
  end
end

puts ShapeFactory.create("square", 3).area
puts ShapeFactory.create("hexagon", 3).inspect

Ausgabe:

9
nil

Ein Hash, der Namen Klassen zuordnet, macht die Factory kürzer und leichter erweiterbar. Klassen sind Objekte, daher können sie in einem Hash gespeichert und new gesendet werden:

class Dog
  def speak
    "Woof"
  end
end

class Cat
  def speak
    "Meow"
  end
end

class AnimalFactory
  KINDS = { "dog" => Dog, "cat" => Cat }.freeze

  def self.create(kind)
    klass = KINDS.fetch(kind) { raise ArgumentError, "unknown animal: #{kind}" }
    klass.new
  end
end

puts AnimalFactory.create("cat").speak
begin
  AnimalFactory.create("cow")
rescue ArgumentError => e
  puts e.message
end

Ausgabe:

Meow
unknown animal: cow

Eine Fabrik kann anderem Code auch erlauben, zur Laufzeit neue Arten zu registrieren, sodass das Hinzufügen einer Art nicht bedeutet, die Fabrik zu bearbeiten:

class Plugins
  @kinds = {}

  class << self
    def register(name, klass)
      @kinds[name] = klass
    end

    def build(name)
      @kinds.fetch(name).new
    end

    def names
      @kinds.keys.sort
    end
  end
end

class Zip
  def run
    "zipping"
  end
end

Plugins.register("zip", Zip)
puts Plugins.build("zip").run
p Plugins.names

Ausgabe:

zipping
["zip"]

Die Aufrufer hängen nur davon ab, was die Objekte tun können, hier area oder speak, und niemals von den konkreten Klassen. Eine neue Form bedeutet eine neue Klasse und einen neuen Eintrag in der Factory, ohne dass irgendwo anders Änderungen erforderlich sind:

shape = ShapeFactory.create(kind, size)   # Square, Circle, ...
puts shape.area                           # der Aufrufer nennt nie eine Klasse
challenge icon

Aufgabe

Einfach

Vervollständige die Formen und ShapeFactory.create(kind, size). Square, Circle und Triangle (gleichseitig) verwenden die Basisklasse Shape, deren to_s square 3: area 9.00 zurückgibt, mit dem Klassennamen in Kleinbuchstaben, der Größe und der Fläche mit zwei Dezimalstellen. Verwende 3.14159 für Pi und Math.sqrt(3) / 4 * size**2 für das Dreieck. Die Factory sucht die Art in einer eingefrorenen Hash-Konstanten KINDS und gibt bei einer unbekannten Art nil zurück.

Der bereitgestellte Code liest Zeilen square 3, fragt die Factory für jede Form ab und gibt sie aus oder unknown shape: hexagon.

Dein Code gehört in shape.rb, square.rb, circle.rb, triangle.rb und shape_factory.rb. main.rb enthält den bereitgestellten Eingabe-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

require_relative 'shape'
require_relative 'square'
require_relative 'circle'
require_relative 'triangle'
require_relative 'shape_factory'

# Mitgelieferter Ein-/Ausgabe-Code: belasse ihn wie er ist
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  kind, size = line.split
  shape = ShapeFactory.create(kind, size.to_f)
  puts shape || "unknown shape: #{kind}"
end
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Ruby-Compiler