จัดการ Object ที่ซับซ้อนให้ง่ายขึ้นด้วย Builder Design Pattern

7 นาที 14 views บันทึกเป็น PDF
จัดการ Object ที่ซับซ้อนให้ง่ายขึ้นด้วย Builder Design Pattern

เบื่อไหมกับ Constructor ที่ยาวเป็นหางว่าว? มาเรียนรู้วิธีใช้ Builder Design Pattern เพื่อสร้าง Object อย่างเป็นระเบียบ อ่านง่าย และลดบั๊กในโปรเจกต์ของคุณ

ทำไมการสร้าง Object ซับซ้อนถึงเป็นเรื่องปวดหัว

เวลาเราเขียนโปรแกรม เรามักจะเริ่มจากการสร้าง Object (กลุ่มข้อมูลและพฤติกรรมที่เก็บไว้ด้วยกัน) แบบง่ายๆ เช่น ตัวเลขหรือข้อความ แต่พอโปรเจกต์เริ่มใหญ่ขึ้น เรามักจะต้องสร้าง Object ที่มีรายละเอียดเยอะมาก เช่น การตั้งค่าหน้าจอ Carousel (แถบเลื่อนรูปภาพ) ที่ต้องกำหนดทั้งความสูง, จำนวนรูป, ความเร็วในการเลื่อน และปุ่มกดต่างๆ

การสร้าง Object เหล่านี้ด้วยวิธีปกติ มักจะจบลงด้วยการเขียน Constructor (ฟังก์ชันเริ่มต้นที่ใช้สร้าง Object) ที่มีพารามิเตอร์ (ค่าที่ส่งเข้าไปในฟังก์ชัน) ยาวเป็นหางว่าว วิธีนี้ทำให้โค้ดอ่านยากมาก เพราะเราต้องจำให้ได้ว่าค่าไหนคืออะไร และถ้าต้องส่งค่าว่างหรือ null (ค่าที่ไม่มีข้อมูล) เข้าไปบ่อยๆ โค้ดของเราจะดูรกและพังได้ง่ายในอนาคต

ปัญหาที่ตามมาคือความยากในการบำรุงรักษา เมื่อโปรเจกต์โตขึ้นแล้วเราต้องการเพิ่มเงื่อนไขใหม่ๆ เราจะต้องกลับไปแก้ที่ตัว Constructor เดิม ซึ่งอาจจะไปกระทบกับส่วนอื่นของโปรแกรมที่ใช้งานอยู่ก่อนแล้ว ทำให้เกิดบั๊ก (ข้อผิดพลาดในโปรแกรม) ได้ง่ายโดยไม่ตั้งใจ The Builder Design Pattern จึงถูกสร้างขึ้นมาเพื่อแก้ปัญหานี้โดยเฉพาะ

รู้จักกับ Builder Pattern แบบเข้าใจง่าย

ลองจินตนาการว่าคุณกำลังสั่งพิซซ่า ถ้าคุณต้องตะโกนบอกส่วนผสมทั้งหมดในลมหายใจเดียวให้พนักงานจด (เหมือน Constructor) คุณมีโอกาสลืมใส่ซอสหรือบอกขนาดผิดสูงมาก แต่ถ้าคุณใช้ใบรายการที่ให้ติ๊กเลือกทีละอย่าง เช่น เลือกแป้ง, เลือกซอส, เลือกหน้า, เลือกเครื่องดื่ม นั่นคือหลักการของ Builder Pattern

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

หัวใจสำคัญคือการแยก Representation (รูปแบบของ Object) ออกจาก Construction (ขั้นตอนการประกอบร่าง) ทำให้เราสามารถสร้าง Object เดียวกันแต่มีค่าข้างในต่างกันได้ง่ายๆ โดยใช้พิมพ์เขียวเดียวกัน ซึ่งช่วยให้โค้ดมีความยืดหยุ่นสูงมากเมื่อต้องทำงานในโปรเจกต์จริง

ส่วนประกอบหลักที่คุณต้องรู้

การจะทำ Builder Pattern ให้ได้ผล เราต้องมีตัวละครหลัก 3 ตัว อย่างแรกคือ Product (ตัว Object ปลายทาง) ซึ่งเป็นเป้าหมายที่เราต้องการสร้าง และมักจะถูกสร้างผ่าน Constructor แบบส่วนตัวเพื่อให้แน่ใจว่าต้องผ่าน Builder เท่านั้น

ตัวที่สองคือ Builder (ตัวประกอบร่าง) ซึ่งเป็นคลาสที่มีหน้าที่เก็บค่าต่างๆ ไว้ชั่วคราว แต่ละเมธอด (ฟังก์ชันในคลาส) จะรับค่าเข้ามาแล้วเก็บไว้ในตัวแปรของตัวเอง พร้อมกับส่งตัวเองกลับออกไปเพื่อให้เราเรียกคำสั่งต่อไปได้ทันที ส่วนตัวที่สามคือ Director (ตัวสั่งงาน) ที่ทำหน้าที่เป็นสูตรสำเร็จในการสร้างค่ามาตรฐาน

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

สร้างความลื่นไหลด้วย Method Chaining

Method Chaining (การเรียกฟังก์ชันต่อกันเป็นทอดๆ) คือเคล็ดลับที่ทำให้ Builder Pattern ดูสวยงามและอ่านง่าย มันทำงานโดยการให้ทุกฟังก์ชันใน Builder ส่งค่า this (อ้างอิงถึงตัวคลาสปัจจุบัน) กลับออกมาเสมอ ทำให้เราสามารถเขียนโค้ดต่อกันได้ยาวๆ ในบรรทัดเดียว

ลองดูตัวอย่างการสร้างคำสั่ง HTTP Request (คำสั่งดึงข้อมูลจากอินเทอร์เน็ต) แบบปกติเทียบกับแบบใช้ Builder จะเห็นความแตกต่างชัดเจนมากครับ แบบแรกเราต้องจำลำดับพารามิเตอร์ แต่แบบที่สองเราอ่านแค่ชื่อฟังก์ชันก็รู้เลยว่ากำลังตั้งค่าอะไร

// ตัวอย่างการสร้าง Request แบบใช้ Builder
final request = RequestBuilder()
  .setUrl('https://api.example.com')
  .setMethod('POST')
  .addHeader('Auth', 'Token123')
  .build(); // สั่งให้สร้าง Object จริงๆ ออกมา

จากโค้ดด้านบน RequestBuilder() คือการเริ่มสร้างตัวช่วย, .setUrl() คือการระบุที่อยู่, .addHeader() คือการเพิ่มข้อมูลความปลอดภัย และ .build() คือขั้นตอนสุดท้ายที่เปลี่ยนการตั้งค่าทั้งหมดให้กลายเป็น Object จริงๆ ผลลัพธ์ที่ได้คือ Object ของ Request ที่พร้อมใช้งานโดยไม่ต้องลุ้นว่าเราใส่ค่าผิดตำแหน่งไหม

ตัวอย่างจริง: การสร้าง Carousel ใน Flutter

ในงานพัฒนาแอปด้วย Flutter (เครื่องมือสร้างแอปมือถือ) เรามักต้องสร้างแถบรูปภาพที่ตั้งค่าได้หลายแบบ Builder Pattern ช่วยให้เราสร้าง Carousel สองแบบที่ต่างกัน เช่น แบบสำหรับโฆษณา และแบบสำหรับแสดงยอดเงิน ได้โดยใช้โค้ดชุดเดียวกัน

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

// ตัวอย่างโครงสร้างคลาสสำหรับเก็บค่า
class CarouselOptions {
  final double height;
  final bool autoplay;
  // ใส่ค่าที่จำเป็นอื่นๆ ไว้ที่นี่
  const CarouselOptions({this.height = 200, this.autoplay = false});
}

นี่คือการเตรียม Configuration Object (ตัวเก็บค่าตั้งค่า) ที่ทำหน้าที่เก็บข้อมูลไว้เฉยๆ ไม่มีการประมวลผล ทำให้เราสามารถส่งต่อค่าเหล่านี้ไปสร้าง Carousel ได้อย่างมั่นใจว่าข้อมูลถูกต้องและครบถ้วนตามที่กำหนดไว้ครับ

สรุป: เมื่อไหร่ที่ควรใช้ Builder Pattern

อย่าพยายามใช้ Builder Pattern กับทุกอย่างในโปรแกรม เพราะมันจะทำให้โค้ดเยอะเกินความจำเป็น ให้ใช้เมื่อคุณต้องสร้าง Object ที่มีพารามิเตอร์มากกว่า 4-5 ตัวขึ้นไป หรือเมื่อ Object นั้นมีค่าที่เป็น Optional (ค่าที่ใส่ก็ได้หรือไม่ใส่ก็ได้) จำนวนมาก

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

จำไว้ว่าเป้าหมายสูงสุดคือการทำให้โค้ดอ่านง่ายและดูแลต่อได้ง่าย หากคุณพบว่าตัวเองต้องเขียนโค้ดสร้าง Object ยาวๆ แล้วเริ่มสับสนว่าค่าไหนทำหน้าที่อะไร นั่นคือสัญญาณเตือนว่าถึงเวลาที่คุณควรนำ Builder Pattern มาใช้ในโปรเจกต์ของคุณแล้วครับ


ที่มา: The Builder Design Pattern: A Better Approach to Complex Object Construction — freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

จัดการเซิร์ฟเวอร์ผ่าน VS Code ให้ง่ายขึ้นด้วย Easy SSH พร้อมฟีเจอร์โหลดไฟล์ผ่านคลิกเดียว

จัดการเซิร์ฟเวอร์ผ่าน VS Code ให้ง่ายขึ้นด้วย Easy SSH พร้อมฟีเจอร์โหลดไฟล์ผ่านคลิกเดียว

เบื่อไหมที่ต้องสลับหน้าจอไปมาเพื่อจัดการเซิร์ฟเวอร์? มาลองใช้ Easy SSH ปลั๊กอิน VS Code ที่ช่วยให้คุณรีโมทผ่าน Terminal ได้สะดวก แถมโหลดไฟล์ได้ง่ายแค่กด Ctrl+click

ที่มา: DEV Community

3 hours ago 11 นาที
3 views
วิธีดึงข้อมูลราคาจาก Google Hotels ด้วย API สำหรับนักพัฒนา

วิธีดึงข้อมูลราคาจาก Google Hotels ด้วย API สำหรับนักพัฒนา

อยากทำแอปท่องเที่ยวแต่ดึงข้อมูลราคาจาก Google Hotels ไม่ได้? มาดูวิธีใช้ Apify Actor ช่วยดึงข้อมูลแบบอัตโนมัติด้วย Python ง่ายๆ ไม่ต้องกลัวเว็บพัง

ที่มา: DEV Community

6 hours ago 8 นาที
4 views
วิธีเช็กความพร้อมโปรเจกต์ก่อนปล่อยงานจริงด้วย ReleaseReady

วิธีเช็กความพร้อมโปรเจกต์ก่อนปล่อยงานจริงด้วย ReleaseReady

เคยไหม? โค้ดรันได้ในเครื่องแต่พอปล่อยจริงกลับพัง! มาดูวิธีตรวจสอบความพร้อมของโปรเจกต์ก่อนอัปขึ้น GitHub ด้วยเครื่องมือ ReleaseReady กัน

ที่มา: DEV Community

10 hours ago 9 นาที
5 views