Menu
CoddyTech

팩토리 패턴

Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 43번째.

팩토리 패턴은 객체 생성을 한곳에서 처리합니다. 호출자는 필요한 것을 요청하고, 흔히 이름으로 지정하며, 어떤 클래스가 만들어졌는지 알지 못한 채 준비된 객체를 받습니다:

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

출력:

9
nil

이름에서 클래스로 매핑하는 해시를 사용하면 팩터리가 더 짧아지고 확장하기도 쉬워집니다. 클래스는 객체이므로 해시에 저장하고 new를 보낼 수 있습니다.

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

출력:

Meow
unknown animal: cow

팩토리를 사용하면 다른 코드가 실행 중에 새로운 종류를 등록할 수도 있으므로, 종류를 추가하기 위해 팩토리를 수정할 필요가 없습니다:

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

출력:

zipping
["zip"]

호출하는 쪽은 객체가 할 수 있는 일, 여기서는 area 또는 speak에만 의존하며, 구체적인 클래스에는 절대 의존하지 않습니다. 새 도형을 추가하려면 클래스 하나와 팩토리에 항목 하나만 추가하면 되며, 다른 곳은 전혀 변경할 필요가 없습니다:

shape = ShapeFactory.create(kind, size)   # Square, Circle, ...
puts shape.area                           # 호출자는 클래스 이름을 직접 지정하지 않는다
challenge icon

챌린지

쉬움

도형과 ShapeFactory.create(kind, size)를 완성하세요. Square, Circle, Triangle(정삼각형)은 기본 클래스 Shape를 공유하며, to_s는 클래스 이름을 소문자로, 크기와 넓이를 소수점 둘째 자리까지 표시한 square 3: area 9.00를 반환합니다. 원주율에는 3.14159를 사용하고, 삼각형에는 Math.sqrt(3) / 4 * size**2를 사용하세요. 팩터리는 고정된 해시 상수 KINDS에서 종류를 찾고, 알 수 없는 종류에는 nil을 반환합니다.

제공된 코드는 square 3과 같은 줄을 읽고, 각 도형을 팩터리에 요청해 출력하거나 unknown shape: hexagon을 출력합니다.

코드는 shape.rb, square.rb, circle.rb, triangle.rb, shape_factory.rb에 작성하세요. main.rb에는 제공된 입력/출력 코드가 들어 있으며 수정할 수 없습니다.

직접 해보기

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

# 제공된 입력/출력 코드: 그대로 유지하세요
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 icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Ruby 컴파일러