Menu
Coddy logo textTech

빌더 패턴

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

빌더 패턴은 복잡한 객체를 단계별로 생성합니다. 각 단계는 하나의 선택 사항을 저장하고 빌더를 반환하는 메서드이므로 단계들이 연결됩니다. build는 선택 사항을 확인하고 완성된 객체를 반환합니다:

class Pizza
  def initialize(size, toppings)
    @size = size
    @toppings = toppings
  end

  def to_s
    "#{@size} pizza with #{@toppings.join(", ")}"
  end
end

class PizzaBuilder
  def initialize
    @toppings = []
  end

  def size(value)
    @size = value
    self
  end

  def topping(name)
    @toppings << name
    self
  end

  def build
    raise ArgumentError, "size is required" if @size.nil?

    Pizza.new(@size, @toppings)
  end
end

puts PizzaBuilder.new.size("large").topping("cheese").topping("ham").build

출력:

large pizza with cheese, ham

빌더는 build에서만 객체를 생성하므로, 필수 구성 요소나 함께 사용할 수 없는 두 옵션과 같은 전체 조합을 한 번에 확인할 수 있습니다:

class TicketBuilder
  def seat(value)
    @seat = value
    self
  end

  def standing
    @standing = true
    self
  end

  def build
    raise ArgumentError, "seat and standing exclude each other" if @seat && @standing

    @standing ? "standing ticket" : "ticket for seat #{@seat || "any"}"
  end
end

puts TicketBuilder.new.seat("B7").build
puts TicketBuilder.new.standing.build
begin
  TicketBuilder.new.seat("A1").standing.build
rescue ArgumentError => e
  puts e.message
end

출력:

ticket for seat B7
standing ticket
seat and standing exclude each other

일반적인 Ruby 형식에서는 빌더를 블록에 전달합니다. 클래스 메서드는 빌더를 생성하고, 빌더를 yield한 다음 마지막에 build를 호출합니다:

class Email
  attr_accessor :to, :subject, :lines

  def self.compose
    email = new
    email.lines = []
    yield email
    email
  end

  def to_s
    "To: #{to}\nSubject: #{subject}\n\n#{lines.join("\n")}"
  end
end

mail = Email.compose do |e|
  e.to = "ada@x.io"
  e.subject = "Hi"
  e.lines << "Hello Ada,"
  e.lines << "see you soon."
end
puts mail

출력:

To: ada@x.io
Subject: Hi

Hello Ada,
see you soon.

몇 가지 선택적 값만 다룰 때는 기본값이 있는 Ruby의 키워드 인수로 충분한 경우가 많습니다. 부분을 반복할 수 있거나, 순서가 중요하거나, 객체가 생성되기 전에 조합을 검증해야 할 때는 빌더가 유용합니다:

Pizza.new(size: "large", crust: "thin")          # 적은 옵션: 키워드

Query.new.from("users").where("age > 18").where("active = 1").limit(10).to_s
challenge icon

챌린지

쉬움

PizzaBuilder와 Pizza를 완성하세요. 빌더의 단계인 size(value), crust(value) 및 topping(name)(반복 가능)는 빌더를 반환합니다. build는 크기가 지정되지 않은 경우 size is required와 함께 ArgumentError를 발생시키고, 크러스트가 선택되지 않은 경우 classic 크러스트를 사용하며, Pizza를 반환합니다. Pizza#to_s는 large thin pizza with cheese, ham 또는 small classic pizza with no toppings을 반환합니다.

각 입력 줄은 size=large crust=thin topping=cheese topping=ham과 같은 하나의 주문입니다. 제공된 코드는 각 부분을 순서대로 체이닝하여 빌더에 전달하고, 피자 또는 오류 메시지를 출력합니다.

코드는 pizza.rb와 pizza_builder.rb에 작성하세요. main.rb에는 제공된 입력/출력 코드가 포함되어 있으며 편집할 수 없습니다.

직접 해보기

require_relative 'pizza'
require_relative 'pizza_builder'

# 제공된 입력/출력 코드: 그대로 유지하세요
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  builder = line.split.reduce(PizzaBuilder.new) do |b, part|
    step, value = part.split("=")
    b.public_send(step, value)
  end
  begin
    puts builder.build
  rescue ArgumentError => e
    puts e.message
  end
end
quiz icon실력 점검

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

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

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