iT邦幫忙

2022 iThome 鐵人賽

DAY 10
0
自我挑戰組

Ruby OOP to Oops !n 30系列 第 10

IT 邦鐵人賽 Day 10 - Abstract factory pattern

  • 分享至 

  • xImage
  •  

抽象工廠(Abstract factory)

目的:

以同一個介面來建立一整族相關或相依的物件,不需要點明個物件真正所屬的具象類別。

結構:

https://ithelp.ithome.com.tw/upload/images/20220925/20151094ovYRzrkqjP.png

程式碼範例

class AbstractFactory
  def create_product_a
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  def create_product_b
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

class ConcreteFactory1 < AbstractFactory
  def create_product_a
    ConcreteProductA1.new
  end

  def create_product_b
    ConcreteProductB1.new
  end
end

class ConcreteFactory2 < AbstractFactory
  def create_product_a
    ConcreteProductA2.new
  end

  def create_product_b
    ConcreteProductB2.new
  end
end

class AbstractProductA

  def useful_function_a
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

class ConcreteProductA1 < AbstractProductA
  def useful_function_a
    'The result of the product A1.'
  end
end

class ConcreteProductA2 < AbstractProductA
  def useful_function_a
    'The result of the product A2.'
  end
end

class AbstractProductB
  def useful_function_b
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  def another_useful_function_b(_collaborator)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

class ConcreteProductB1 < AbstractProductB
  def useful_function_b
    'The result of the product B1.'
  end

  def another_useful_function_b(collaborator)
    result = collaborator.useful_function_a
    "The result of the B1 collaborating with the (#{result})"
  end
end

class ConcreteProductB2 < AbstractProductB
  def useful_function_b
    'The result of the product B2.'
  end

  def another_useful_function_b(collaborator)
    result = collaborator.useful_function_a
    "The result of the B2 collaborating with the (#{result})"
  end
end

def client_code(factory)
  product_a = factory.create_product_a
  product_b = factory.create_product_b

  puts product_b.useful_function_b.to_s
  puts product_b.another_useful_function_b(product_a).to_s
end

puts 'Client: Testing client code with the first factory type:'
client_code(ConcreteFactory1.new)

puts "\n"

puts 'Client: Testing the same client code with the second factory type:'
client_code(ConcreteFactory2.new)

結果

Client: Testing client code with the first factory type:
The result of the product B1.
The result of the B1 collaborating with the (The result of the product A1.)

Client: Testing the same client code with the second factory type:
The result of the product B2.
The result of the B2 collaborating with the (The result of the product A2.)

解釋

在討論整個抽象工廠運作流程以前,最重要的是先了解客戶端如何啟動抽象工廠!
上述的程式碼中的client_code內所投入的factory參數,是工廠運作的開始,也是確立哪一個工廠應該開始作用
確認工廠後再來就是確認哪種產品是需要的,所以再來使用create_product_a或者create_product_b來製作特定產品
而製造產品的方法內部細節,會額外抽離到ConcreteProduct的類別之中
最後獲得產品物件後,就可以實踐各個方法

此外Abstract的部分是宣告抽象介面,利用與Concrete繼承關係,來讓客戶端知道哪些工廠或者產品可以實作
Concrete則是負責實作具象成品(所以客戶端在產生物件時,會直接new出特定工廠來實作特定產品)

優點

  1. 因為client端所輸入的是特定工廠,所以確保一系列產品的產出
  2. 避免client與產品耦合
  3. SRP,工廠跟產品職責分離
  4. Open/Closed Principle,可以隨時增加工廠與其產品,不用擔心修改其他工廠或產品的內容

明天又要上班囉,大家早點休息吧~ :)

感謝大家 如有問題,再煩請大家指教!


上一篇
IT 邦鐵人賽 Day 9 - SOLID
下一篇
IT 邦鐵人賽 Day 11 - Builder
系列文
Ruby OOP to Oops !n 3020
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Jean_HSU
iT邦新手 5 級 ‧ 2022-09-26 22:57:56

喳喳喳

我要留言

立即登入留言