Menu
CoddyTech

Pola Decorator

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Ruby di Coddy. Pelajaran 47 dari 57.

Pola decorator membungkus sebuah object dengan object lain yang memiliki antarmuka yang sama, sehingga menambahkan sesuatu sebelum atau sesudah meneruskan pemanggilan. Decorator dapat ditumpuk dalam urutan apa pun:

class Coffee
  def cost
    2.0
  end

  def description
    "coffee"
  end
end

class Milk
  def initialize(drink)
    @drink = drink
  end

  def cost
    @drink.cost + 0.5
  end

  def description
    "#{@drink.description}, milk"
  end
end

order = Milk.new(Milk.new(Coffee.new))
puts format("%s: %.2f", order.description, order.cost)

Output:

coffee, milk, milk: 3.00

Setiap decorator menyimpan object yang dibungkus dan meneruskan pemanggilan kepadanya, jadi base class bersama dapat menampung bagian tersebut. Lalu, setiap decorator konkret hanya meng-override hal yang diubahnya:

class Coffee
  def cost
    2.0
  end

  def description
    "coffee"
  end
end

class Extra
  def initialize(drink)
    @drink = drink
  end

  def cost
    @drink.cost
  end

  def description
    @drink.description
  end
end

class Sugar < Extra
  def cost
    super + 0.2
  end

  def description
    super + ", sugar"
  end
end

order = Sugar.new(Coffee.new)
puts format("%s: %.2f", order.description, order.cost)

Output:

coffee, sugar: 2.20

SimpleDelegator dari standard library (require 'delegate') meneruskan setiap method yang tidak didefinisikannya ke object yang dibungkusnya. Ini membuat decorator tetap singkat saat antarmukanya besar:

require 'delegate'

class Loud < SimpleDelegator
  def to_s
    super.upcase + "!"
  end
end

text = Loud.new("hello")
puts text
puts text.size
puts text.start_with?("he")

Output:

HELLO!
5
true

Dekorator menambahkan perilaku pada objek tunggal saat runtime dan dapat digabungkan secara bebas. Dengan subclass, setiap kombinasi seperti MilkSugarCoffee akan memerlukan class tersendiri:

Sugar.new(Milk.new(Coffee.new))      # kombinasi apa pun, urutan apa pun
Whip.new(Sugar.new(Coffee.new))

# dengan subclass: MilkCoffee, SugarCoffee, MilkSugarCoffee, ...
challenge icon

Tantangan

Mudah

Lengkapi decorator kopi. Coffee berharga 2.00 dan dideskripsikan sebagai coffee. Milk menambahkan 0.50 dan , milk, Sugar menambahkan 0.20 dan , sugar, dan Whip menambahkan 0.70 dan , whip. Ketiga decorator menggunakan class dasar Extra, yang menyimpan minuman yang dibungkus dan meneruskan cost dan description; setiap subclass menggunakan super.

Setiap baris input adalah pesanan seperti milk sugar. Kode yang disediakan membungkus Coffee baru dengan decorator sesuai urutan tersebut, lalu mencetak coffee, milk, sugar: 2.70.

Tulis kodemu di coffee.rb, extra.rb, milk.rb, sugar.rb, dan whip.rb. main.rb berisi kode input/output yang disediakan dan tidak dapat diedit.

Coba sendiri

require_relative 'coffee'
require_relative 'extra'
require_relative 'milk'
require_relative 'sugar'
require_relative 'whip'

# Kode input/output yang disediakan: biarkan apa adanya
input = []
while (line = gets)
  input << line.chomp
end
extras = { "milk" => Milk, "sugar" => Sugar, "whip" => Whip }
input.each do |line|
  drink = line.split.reduce(Coffee.new) { |d, name| extras[name].new(d) }
  puts format("%s: %.2f", drink.description, drink.cost)
end
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Ruby online