ข้ามไปยังเนื้อหา

Introduce Parameter Object

มองหากลุ่ม argument ที่โผล่มาด้วยกันซ้ำ ๆ ในหลาย function แล้วแทนด้วย object ตัวเดียวที่เก็บค่าทั้งชุดไว้ กลุ่มนั้นจะได้ชื่อ ความสัมพันธ์ระหว่างค่าจะชัดขึ้น และ function ที่เคยรับ argument กระจัดกระจาย ก็เหลือรับ parameter เรียบร้อยตัวเดียว

ท่านี้รักษา Long Parameter List กับญาติคือ Data Clump ซึ่งก็คือค่าสองสามตัวเดิม ๆ ที่ถูกส่งเรียงติดกันตามลำดับเดิม ไล่ไปทีละ function เช่น start กับ end ที่จริง ๆ แล้วคือ ช่วงวันที่ หรือ latitude กับ longitude ที่จริง ๆ แล้วคือ ตำแหน่ง พอค่าหลายตัวเดินทางกันเป็นฝูง ฝูงนั้นคือแนวคิดที่ code ยังไม่ได้ตั้งชื่อ ที่แย่กว่านั้นคือรายการยาว ๆ ที่ไม่มีชื่อกำกับ ยังเชิญชวนให้เกิดความผิดพลาดคลาสสิกอย่างการส่ง argument สลับลำดับ

การจองเที่ยวบินที่ลาก argument สี่ตัวซึ่งเกี่ยวข้องกันหลวม ๆ ไปไหนมาไหน หลัง refactor ทั้งหมดยุบเหลือ object Trip ตัวเดียว

// Before
function bookFlight(
from: string,
to: string,
startDate: string,
endDate: string,
): string {
return `Flight ${from}->${to} from ${startDate} to ${endDate}`;
}
const summary = bookFlight("BKK", "NRT", "2026-07-01", "2026-07-09");
// After
interface Trip {
from: string;
to: string;
startDate: string;
endDate: string;
}
function bookFlight(trip: Trip): string {
return `Flight ${trip.from}->${trip.to} from ${trip.startDate} to ${trip.endDate}`;
}
const summary = bookFlight({
from: "BKK",
to: "NRT",
startDate: "2026-07-01",
endDate: "2026-07-09",
});
flowchart LR
  subgraph Before["Before"]
    A["bookFlight(<br/>from, to,<br/>startDate, endDate)"]
  end
  subgraph After["After"]
    B["bookFlight(trip)"]
    B --> C["Trip<br/>{ from, to,<br/>startDate, endDate }"]
  end
  Before -.->|"Introduce Parameter Object"| After
argument กระจัดกระจายสี่ตัวกลายเป็น object Trip ที่มีชื่อเพียงตัวเดียว
  1. ระบุกลุ่มให้ได้ก่อน คือ argument ที่โผล่มาด้วยกันเสมอ แล้วตั้งชื่อให้แนวคิดที่กลุ่มนั้นแทน
  2. สร้างโครงสร้างใหม่ (class, struct, record หรือ interface) ที่มี field สำหรับสมาชิกแต่ละตัวของกลุ่ม
  3. เพิ่ม object ใหม่เป็น parameter ให้ function เป้าหมายตัวหนึ่ง โดยตอนแรกวางไว้ข้าง ๆ argument เดิม รัน test
  4. ภายในเนื้อใน ให้เริ่มอ่านจาก field ของ object แทน parameter ที่กระจัดกระจาย ทีละ field โดย test ไปเรื่อย ๆ ขณะทำ
  5. เมื่อเนื้อในอ่านจาก object เพียงอย่างเดียวแล้ว ให้ลบ parameter ที่กระจัดกระจายซึ่งไม่ได้ใช้แล้วออกจากลายเซ็น จากนั้นอัปเดต caller ของ function นั้นให้สร้างและส่ง object
  6. ทำซ้ำกับ function อื่น ๆ ที่ใช้กลุ่มเดียวกัน เพื่อให้ทั้งหมดรับ object
  7. รัน test หลังแก้แต่ละ function และคอยสังเกต behavior ใหม่ที่ผุดขึ้นมา เพราะพอข้อมูลมารวมกันแล้ว logic ที่ทำงานกับข้อมูลชุดนั้นมักอยากย้ายเข้าไปอยู่บน object ตามไปด้วย

แนะนำให้ใช้ parameter object เมื่อค่าชุดเดิมถูกส่งด้วยกันซ้ำ ๆ เมื่อรายการ parameter ยาวจน caller ส่งลำดับผิด หรือเมื่อคุณรู้สึกได้ว่ามีแนวคิดที่ยังไม่ได้ตั้งชื่อซ่อนอยู่ในรายการ argument object บันทึกความสัมพันธ์ไว้และให้ที่อยู่ตามธรรมชาติแก่ behavior ที่เป็นของกลุ่มนั้น

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

ใช้ Introduce Parameter Object เมื่อหลีกเลี่ยงเมื่อ
parameter กลุ่มเดียวกันปรากฏในหลาย functionparameter ที่จะรวมไม่มี cohesion จริง ๆ
function มี parameter เกิน 3-4 ตัวobject ใหม่จะมีแค่ data ไม่มี behavior
parameter แต่ละตัวมีความสัมพันธ์กัน (date range, point)มีแค่ 2 parameter และมักเปลี่ยนแยกกัน

⚠️ ไม่ควร Introduce Parameter Object เมื่อ:

  • parameter ที่รวมกันไม่ได้ปรากฏพร้อมกันเสมอ
  • object ใหม่จะไม่มี behavior ที่เกี่ยวข้อง — แค่ data bag
  • function นั้นเป็น one-off ที่ไม่ถูกเรียกจากหลายที่
Introduce Parameter Object จัดการกับกลิ่นใดเป็นหลัก?
ทำไมกลุ่มของ argument ที่เดินทางไปด้วยกันเสมอจึงมีนัยสำคัญ?
อะไรมักเกิดขึ้นหลังจากข้อมูลถูกจัดเข้าเป็น object เดียว?
เมื่อใดที่การนำ parameter object เข้ามาอาจไม่คุ้มค่า?