제이온

[Effective Java] รายการที่ 2: พิจารณาการใช้ Builder เมื่อมีพารามิเตอร์ใน Constructor จำนวนมาก

สร้าง: 2024-04-27

สร้าง: 2024-04-27 00:46

รูปแบบตัวสร้างแบบเพิ่มทีละขั้น (Incremental Builder Pattern)

ทั้งตัวสร้างแบบคงที่ (Static Factory) และตัวสร้าง (Constructor) ล้วนมีข้อจำกัดในการจัดการพารามิเตอร์จำนวนมากได้อย่างเหมาะสม หากสมมติว่าคลาสมีฟิลด์ 6 ฟิลด์ และต้องการสร้างตัวสร้างแยกกันสำหรับกรณีที่พารามิเตอร์มี 2 ตัว 3 ตัว ฯลฯ สามารถใช้รูปแบบตัวสร้างแบบเพิ่มทีละขั้นได้ดังตัวอย่างต่อไปนี้



แต่ถึงอย่างนั้น หากพารามิเตอร์มีจำนวนมากขึ้น ก็อาจทำให้เกิดความสับสนในการอ่านโค้ดว่าแต่ละค่ามีความหมายอย่างไร และอาจทำให้เกิดความผิดพลาดจากการใส่ค่าพารามิเตอร์ที่ชนิดข้อมูลเหมือนกันผิดที่ผิดทางได้


รูปแบบ Java Beans

รูปแบบ Java Beans สร้างออบเจ็กต์โดยใช้ตัวสร้างที่ไม่มีพารามิเตอร์ จากนั้นจึงเรียกใช้เมธอด setter เพื่อกำหนดค่าพารามิเตอร์ที่ต้องการ



รูปแบบ Java Beans ช่วยให้ไม่สับสนในการสร้างอินสแตนซ์แม้ว่าพารามิเตอร์จะมีจำนวนมากขึ้น แต่ก็ต้องเรียกใช้เมธอด setter หลายครั้งเพื่อสร้างออบเจ็กต์เพียงหนึ่งเดียว และความสอดคล้องกันของออบเจ็กต์อาจเสียไปก่อนที่มันจะเสร็จสมบูรณ์ ทำให้ไม่สามารถสร้างคลาสให้เป็นแบบคงที่ (Immutable) ได้


รูปแบบตัวสร้าง (Builder Pattern)

รูปแบบตัวสร้าง (Builder Pattern) เป็นรูปแบบที่ผสานความปลอดภัยของรูปแบบตัวสร้างแบบเพิ่มทีละขั้น (Incremental Builder Pattern) และความสามารถในการอ่านโค้ดของรูปแบบ Java Beans เข้าด้วยกัน

ไคลเอ็นต์จะไม่สร้างออบเจ็กต์เอง แต่จะเรียกใช้ตัวสร้างด้วยพารามิเตอร์ที่จำเป็นเพื่อรับออบเจ็กต์ตัวสร้าง (Builder Object) จากนั้นจึงใช้เมธอด setter ที่ออบเจ็กต์ตัวสร้างจัดเตรียมไว้เพื่อกำหนดค่าพารามิเตอร์ที่เลือกได้ และสุดท้ายก็เรียกใช้เมธอด build() ที่ไม่มีพารามิเตอร์เพื่อรับออบเจ็กต์ที่ต้องการ



คลาส Builder มีตัวสร้างที่รับพารามิเตอร์ที่จำเป็นเท่านั้น และพารามิเตอร์ที่เลือกได้อื่นๆ จะถูกเติมเต็มโดยเมธอด setter คล้ายๆ กับเมธอด setter และสุดท้ายก็สร้างออบเจ็กต์ NutritionFactsWithBuilderPattern ที่สมบูรณ์แบบโดยใช้เมธอด build() คลาส NutritionFactsWithBuilderPattern เป็นแบบคงที่ (Immutable) และเมธอด setter ของตัวสร้างจะส่งคืนตัวสร้างเอง ทำให้สามารถเรียกใช้แบบต่อเนื่องได้ รูปแบบนี้เรียกว่า Fluent API หรือ Method Chaining



ไคลเอ็นต์สามารถเขียนและอ่านโค้ดได้ง่ายขึ้นด้วยรูปแบบตัวสร้าง (Builder Pattern)


รูปแบบตัวสร้าง (Builder Pattern) เหมาะกับคลาสที่ออกแบบเป็นลำดับชั้น


คลาส Pizza.Builder เป็นคลาสแบบเจเนริกที่มีการใช้ Type Parameter แบบเรียกซ้ำ (Recursive Type Bound) และมีเมธอดนามธรรม self() เพิ่มเข้ามาเพื่อให้คลาสย่อยสามารถสนับสนุนการเรียกใช้แบบต่อเนื่อง (Method Chaining) ได้โดยไม่ต้องแปลงชนิดข้อมูล คลาสย่อยเพียงแค่ส่งคืนค่าของเมธอดนามธรรมนี้เป็นตัวมันเองก็เพียงพอแล้ว

ลองมาดูตัวอย่าง Pizza แบบนิวยอร์กและแบบ Calzone ซึ่งเป็นคลาสย่อยของ Pizza เพื่อดูความยืดหยุ่นของรูปแบบตัวสร้าง (Builder Pattern)



เมธอด build() ที่กำหนดไว้ในตัวสร้างของแต่ละคลาสย่อยจะส่งคืนคลาสย่อยที่เป็นรูปธรรม การที่เมธอดในคลาสย่อยส่งคืนค่าที่เป็นชนิดย่อยแทนที่จะเป็นชนิดของคลาสหลักที่เมธอดของคลาสหลักส่งคืน เรียกว่า Covariant Return Typing คุณสมบัติตัวนี้ทำให้ไคลเอ็นต์ไม่จำเป็นต้องแปลงชนิดข้อมูล



ไคลเอ็นต์สามารถใช้ enum ของ Pizza และ enum ของแต่ละคลาสย่อยร่วมกันได้ และสร้างออบเจ็กต์ให้สมบูรณ์แบบด้วยเมธอดที่เหมาะสม


ข้อเสียของรูปแบบตัวสร้าง (Builder Pattern)

  • ต้องสร้างออบเจ็กต์ตัวสร้าง (Builder Object)
  • โค้ดอาจยาว


สรุป

หากตัวสร้าง (Constructor) หรือเมธอดตัวสร้างแบบคงที่ (Static Factory Method) ต้องจัดการกับพารามิเตอร์จำนวนมาก ควรพิจารณาใช้รูปแบบตัวสร้าง (Builder Pattern)


แหล่งที่มา

  • Effective Java

ความคิดเห็น0

กฎพื้นฐานของ CSS (Normal flow, BFC, IFC)บทความนี้จะอธิบายเกี่ยวกับกฎพื้นฐานของ CSS อย่าง Normal flow, BFC และ IFC พร้อมทั้งให้ความรู้ที่จำเป็นในการสร้างโครงสร้าง Layout และการออกแบบเว็บไซต์แบบ Responsive
뚠뚠멍의 생각들
뚠뚠멍의 생각들
뚠뚠멍의 생각들
뚠뚠멍의 생각들

September 7, 2024

[1 วัน] สร้างเกมสนุกๆ กับ AIขอแนะนำบันทึกการพัฒนาเกมดันเจี้ยน 100 ชั้นที่สร้างด้วย Javascript, HTML, CSS โดยได้รับความช่วยเหลือจาก AI ปัจจุบันกำลังพัฒนาส่วนต่างๆ เช่น เมือง ดันเจี้ยน และระบบต่อสู้ โดยได้เสร็จสิ้นการสร้างระบบสร้างตัวละครและระบบคลังของแล้ว พรุ่งนี้จะเริ่มพัฒนาต่อสู้
꼬반
꼬반
꼬반
꼬반

November 8, 2024

ความแปรปรวนร่วมและความแปรปรวนตรงข้ามบทความนี้จะอธิบายแนวคิดเรื่องความแปรปรวนร่วมและความแปรปรวนตรงข้าม โดยใช้ตัวอย่าง Animal และ Dog เพื่ออธิบายความแปรปรวนร่วมและความแปรปรวนตรงข้าม และเน้นความจำเป็นของความแปรปรวนตรงข้ามเพื่อเพิ่มความยืดหยุ่นในการจัดการเหตุการณ์ ฯลฯ นอกจากนี้ยังกล่าวถึงความแ
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

November 1, 2024

[สำหรับผู้ไม่ใช่ผู้เชี่ยวชาญ ด้านการพัฒนาซอฟต์แวร์ เพื่อความอยู่รอด] 14. สรุปเนื้อหาสัมภาษณ์ทางเทคนิคที่ผู้พัฒนาซอฟต์แวร์มือใหม่ถามบ่อยสรุปคำถามทางเทคนิคที่มักถามในการสัมภาษณ์งานผู้พัฒนาซอฟต์แวร์มือใหม่ (พื้นที่หน่วยความจำ โครงสร้างข้อมูล ฐานข้อมูล ฯลฯ) หวังว่าจะเป็นประโยชน์ในการเตรียมตัวสัมภาษณ์งานด้านการพัฒนา
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

April 3, 2024

LLM สำหรับเด็กประถมคำอธิบายแนวคิด LLM ที่แม้แต่เด็กประถมก็เข้าใจ! LLM คือ AI ที่ตอบคำถามเป็นข้อความเมื่อได้รับคำถามเป็นข้อความ สามารถทำงานได้หลากหลาย เช่น การเขียนโค้ด การวิเคราะห์ภาพ ฯลฯ ปัจจุบันนักพัฒนาใช้ AI เป็นเครื่องมือ
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

March 4, 2025

ยังคงใช้ไลบรารีเชิงฟังก์ชันอยู่หรือไม่แนะนำการเปลี่ยนแปลงของไลบรารีการเขียนโปรแกรมเชิงฟังก์ชันและการถือกำเนิดของ Effect Framework พร้อมทั้งกล่าวถึงความเป็นไปได้ที่จะตั้งมาตรฐานใหม่ในวงการ Node.js
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

July 30, 2024