鴨子型別 - 能做什麼比是什麼重要!


Posted by Nacho on 2020-10-31

TLDR

鴨子型別的物件是按它的行為而非類別來定義
它是一個讓程式設計更靈活的技巧,也可能是維護上的災難

前言

接觸ruby的一大有趣發現就是原來有種東西叫『鴨子型別』。提到型別,開發者一定不陌生,因為型別就是像字串、數字、陣列這些(型別:描述變數內容的分類)。那怎麼會有鴨子型別(Duck Typing)呢?先看一行code

# 假設已有一個食譜類別...
recipe = Recipe.new # 產生一個食譜的實例
recipe.print(Pizza.new) # 把披薩的實例傳給請食譜列出製作步驟
recipe.print(Macaroni.new) # 把通心麵的實例傳給食譜列出製作步驟

可以發現這個食譜就像一個接收器,它可以接收一些東西,然後把東西給印出來!而那個東西就是鴨子型別物件,待會在程式範例有詳細的說明,在這之前先看定義。

鴨子型別 Duck Typing

是種基於從物件導向目的延伸的概念,從它名稱來理解:如果物件叫起像鴨子,走起來像鴨子,它就是一隻鴨子,所以是不是真的鴨子,哪種鴨子,that doesn't matter...行為像就夠了,所以鴨子型別的物件是按它的行為而非類別來定義的。

Duck Typing refers to the tendency of Ruby to be less concerned with the class of an object and more concerned with what methods can be called on it and what operations can be performed on it.

程式範例

下面有一段程式,主要是產生食譜的步驟。這個程式目前有三個食譜(Pizza, GrilledCheese, Macaroni),由於我的目標很明確『印出每個食物的步驟』,它既是期望的目的也是預期的行為,所以有一個 Recipe 的類別,他有一個 prepare 的方法。它負責幫我把食物的製作步驟印出來。然而,特別的地方就在於 Recipe 只要把 food 印出來舊好,至於 food 是什麼,它並不知道!food 代表了鴨子型別的概念,因為他唯一要做的就是實作 steps 的行為,因此可以說 food 像什麽就是什麼,所以 food 可以變成 Pizza, Macaroni 或其他的東西,只要它可以實作 steps 就好了。這樣似乎更能體會『鴨子型別的物件是按它的行為而非類別來定義』的寓意!

# duck_type.rb
class Recipe
  def print(food)
    food.steps
  end

  def prepare(foods)
    foods.each do |food|
      print(food)
    end
  end
end

class Pizza
  def steps
    puts "you watch Pizza"
    puts "spread the sauce"
    puts "sprinkle the cheese"
  end
end

class Macaroni
  def steps
    puts "you watch Macaroni"
    puts "cook the noodles"
    puts "stir in the cheese"
  end
end

class GrilledCheese
  def steps
    puts "you watch GrilledCheese"
    puts "grill the bread"
    puts "melt the cheese"
  end
end

# 可以把下面的程式打在 irb 上看執行結果
# 請先 require_relative 'duck_type.rb'
r = Recipe.new
r.print(Pizza.new)
r.print(Macaroni.new)
r.print(GrilledCheese.new)
r.prepare([GrilledCheese.new, Pizza.new])

心得

最近剛讀完『Ruby 物件導向設計實踐』,邊讀邊讚嘆這種靈活的設計技巧。但 Sandi (作者)也提醒,善用這個觀念能為程式設計上帶來更大的靈活性,但也可能建構出混亂難以維護的設計。我認為先懂得識別這樣的技巧,從觀察別人的code累積一些經驗,等看到足夠多的案例再思考如何運用在開發上。

參考

http://rubylearning.com/satishtalim/duck_typing.html
https://dev.to/middlebrooks314/duck-typing-1gnn


#Duck typing #Ruby OOD #鴨子型別 #ruby







Related Posts

1 個 div 和 4 行 CSS 就能更了解瀏覽器渲染引擎

1 個 div 和 4 行 CSS 就能更了解瀏覽器渲染引擎

資料庫相關專有名詞簡介

資料庫相關專有名詞簡介

C++ 教學(二) 輸入輸出&基本資料型態

C++ 教學(二) 輸入輸出&基本資料型態


Comments