Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط الباني

جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 48 من 57.

ينشئ نمط المنشئ كائنًا معقدًا خطوةً بخطوة. كل خطوة هي طريقة تخزّن خيارًا واحدًا وتُرجع المنشئ، ولذلك تتسلسل الخطوات؛ تتحقق 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 مهمةَ البناء. تنشئ طريقة الصنف أداة البناء، وتمررها إلى الكتلة، وتستدعي 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 الخطأ ArgumentError مع size is required عند عدم تقديم حجم، وتستخدم القشرة 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 عبر الإنترنت