รูปแบบสำหรับการส่งบริบทผ่านห่วงโซ่วิธีการ


19

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

โค้ดตัวอย่างที่ต้องการโซลูชัน

// needs the dependency
function baz(session) {
  session('baz');
}

// doesn't care about the dependency
function bar() {
  baz();
}

// needs the dependency
function foo(session) {
   session('foo')
   bar();
}

// creates the dependency
function start() {
  let session = new Session();
  foo(session);
}

การแก้ปัญหาที่เป็นไปได้

  • ThreadLocal
  • ทั่วโลก
  • วัตถุบริบท
  • ผ่านการพึ่งพาผ่าน
  • baz แกงและส่งผ่านเข้าไปในแถบที่มีการตั้งค่าการอ้างอิงเป็น ARG แรก
  • ฉีดพึ่งพา

ตัวอย่างของที่เกิดขึ้น

การประมวลผลคำขอ HTTP

วัตถุบริบทในรูปแบบของแอตทริบิวต์คำขอมักจะใช้: ดู expressjs, Java Servlets หรือ. owin ของ. net

เข้าสู่ระบบ

สำหรับการบันทึกการใช้ Java มักใช้ globals / singletons ดูรูปแบบการบันทึก / ทั่วไปของ log4j / commons ทั่วไป

การทำธุรกรรม

เธรดเธรดมักใช้เพื่อรักษาธุรกรรมหรือเซสชันที่เชื่อมโยงกับการเรียกใช้เมธอดแบบลูกโซ่เพื่อหลีกเลี่ยงการต้องการส่งผ่านเป็นพารามิเตอร์ไปยังเมธอดทั้งหมดที่ไม่ต้องการ


โปรดใช้ตัวอย่างที่มีความหมายมากขึ้น
Tulains Córdova

ฉันได้เพิ่มตัวอย่างของที่มา
Jamie McCrindle

3
ฉันหมายถึงโค้ดตัวอย่างที่มีความหมายมากกว่า
Tulains Córdova

คำตอบ:


11

คำตอบที่ยุติธรรมเพียงอย่างเดียวคือมันขึ้นอยู่กับสำนวนการเขียนโปรแกรมของคุณ หากคุณกำลังใช้ OO มันแทบจะไม่ถูกต้องแน่นอนที่จะผ่านการพึ่งพาจากวิธีหนึ่งไปอีกวิธีหนึ่ง มันเป็นกลิ่นรหัสใน OO ในความเป็นจริงนั่นเป็นหนึ่งในปัญหาที่ OO แก้ได้ - วัตถุจะแก้ไขบริบท ดังนั้นใน OO วิธีการหนึ่งที่ถูกต้อง (มีวิธีอื่นเสมอ) คือการส่งมอบการพึ่งพาผ่านตัวสร้างหรือทรัพย์สิน ผู้แสดงความคิดเห็นกล่าวถึง "การพึ่งพาการฉีด" และเป็นสิ่งที่ถูกต้องสมบูรณ์ แต่ไม่จำเป็นอย่างยิ่ง เพียงแค่ให้พึ่งพาจึงเป็นใช้ได้ในฐานะที่เป็นสมาชิกและfoobaz

คุณพูดถึงการปิดบังดังนั้นฉันจะสมมติว่าการเขียนโปรแกรมใช้งานได้ไม่เป็นปัญหา ในกรณีดังกล่าวปรัชญาที่เทียบเท่ากับบริบทของวัตถุคือการปิด วิธีการใดก็ตามที่แก้ไขการอ้างอิงเพื่อให้พร้อมใช้งานสำหรับผู้ติดตามซึ่งทำงานได้ดี การแกงเป็นวิธีหนึ่งดังกล่าว (และทำให้คุณฟังดูดี) เพียงจำไว้ว่ามีวิธีอื่นในการปิดการพึ่งพา บางคนก็สง่างามและบางคนก็น่ากลัว

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


การอ้างว่าการผ่านพารามิเตอร์รอบ ๆ ภายในวิธีการของ OO เป็นกลิ่นรหัสเป็นข้อความที่ขัดแย้งกันมาก ฉันขอโต้แย้งในทางตรงกันข้ามอย่างสมบูรณ์: การส่งเสริมสภาพการผสมและการใช้งานภายในชั้นเรียนเป็นหนึ่งในข้อผิดพลาดที่ยิ่งใหญ่ที่สุดที่ทำโดยกระบวนทัศน์ OO และหลีกเลี่ยงโดยการฉีดการพึ่งพาโดยตรงเป็นวิธีการแทนที่จะเป็นคอนสตรัคเตอร์ ของรหัสไม่ว่าจะ OO หรือไม่
David Arno

3
@DavidArno ฉันขอแนะนำให้ใช้กระบวนทัศน์ที่แตกต่างกันเมื่อเทียบกับการสรุปสถานะของวัตถุคือ "หนึ่งในความผิดพลาดที่ยิ่งใหญ่ที่สุดที่ทำโดยกระบวนทัศน์ OO" จากนั้นหลีกเลี่ยงกระบวนทัศน์ ฉันไม่มีอะไรต่อต้านวิธีการใด ๆ แต่โดยทั่วไปแล้วไม่ชอบโค้ดที่ผู้เขียนกำลังต่อสู้กับเครื่องมือของพวกเขา สถานะส่วนตัวเป็นคุณลักษณะที่แตกต่างของ OO หากคุณละทิ้งคุณลักษณะนั้นคุณจะสูญเสียพลังบางส่วนของ OO
Scant Roger

1
@DavidArno คลาสที่มีสถานะทั้งหมดและไม่มีฟังก์ชันการทำงานไม่มีกลไกในการบังคับใช้ความสัมพันธ์ที่ไม่เปลี่ยนแปลงในรัฐ ชั้นเรียนนี้ไม่ได้อยู่ที่ OO เลย
Kevin Krumwiede

@KevinKrumwiede คุณได้ใช้ reducto ad absudium กับความคิดเห็นของฉัน แต่ประเด็นของคุณยังคงดีอยู่ ความไม่แปรเปลี่ยนของรัฐเป็นส่วนสำคัญของการ "ก้าวต่อไปจาก OO" ดังนั้นการหลีกเลี่ยงการผสมฟังก์ชั่นและสถานะจะต้องอนุญาตให้มีการทำงานที่เพียงพอในวัตถุของรัฐตามที่จำเป็นเพื่อให้เกิดความไม่แปรเปลี่ยน (ฟิลด์ที่ห่อหุ้มที่กำหนดโดยผู้สร้าง
David Arno

@ScantRoger ฉันยอมรับกระบวนทัศน์อื่นที่สามารถนำมาใช้คือกระบวนทัศน์การทำงาน ที่น่าสนใจที่สุดภาษา "OO" ที่ทันสมัยมีรายการคุณสมบัติการใช้งานเพิ่มขึ้นดังนั้นจึงเป็นไปได้ที่จะยึดติดกับภาษาเหล่านั้นและปรับใช้กระบวนทัศน์ของฟังก์ชั่นโดยไม่ต้อง "ต่อสู้กับเครื่องมือ"
David Arno

10

ถ้าbarอยู่บนขึ้นbazซึ่งจะต้องdependencyแล้วbarต้องเกินไปเพื่อการใช้งานอย่างถูกต้องdependency bazดังนั้นวิธีการที่ถูกต้องจะส่งผ่านการพึ่งพาผ่านเป็นพารามิเตอร์ไปbarหรือแกงและผ่านที่bazbar

วิธีแรกคือง่ายต่อการใช้และอ่าน แต่สร้างการมีเพศสัมพันธ์ระหว่างและbar bazวิธีที่สองจะลบการเชื่อมต่อนั้น แต่อาจส่งผลให้รหัสชัดเจนน้อยลง วิธีการใดที่ดีที่สุดจึงน่าจะขึ้นอยู่กับความซับซ้อนและพฤติกรรมของทั้งสองฟังก์ชัน ตัวอย่างเช่นหากbazหรือdependencyมีผลข้างเคียงความง่ายในการทดสอบน่าจะเป็นตัวขับเคลื่อนขนาดใหญ่ที่เลือกโซลูชัน

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


1
ฉันเห็นด้วยเกือบทั้งหมด การฉีดพึ่งพาอาจเป็นอีกหนึ่งโปรแกรมที่ไม่ใช่ "แฮ็ค"
Jonathan van de Veen

1
@JanathanvandeVeen แน่นอนว่าการdependencyผ่านพารามิเตอร์ต่างๆเป็นการฉีดที่ต้องพึ่งพาหรือไม่
David Arno

2
@DavidArno กรอบการฉีดพึ่งพาไม่ได้กำจัดการพึ่งพาประเภทนี้พวกเขาเพียงแค่ย้ายพวกเขา ความมหัศจรรย์คือพวกมันเคลื่อนพวกมันออกนอกชั้นเรียนของคุณไปยังสถานที่ซึ่งการทดสอบคือปัญหาของใครบางคน
Kevin Krumwiede

@JonathanvandeVeen ฉันเห็นด้วยการฉีดพึ่งพาเป็นทางออกที่ถูกต้อง ในความเป็นจริงมันเป็นสิ่งที่ฉันมักจะเลือก
Jamie McCrindle

1

การพูดเชิงปรัชญา

ผมเห็นด้วยกับความกังวลของเดวิดอาร์โน

ฉันกำลังอ่าน OP ว่ากำลังมองหาโซลูชันการใช้งาน แต่คำตอบคือการเปลี่ยนแปลงการออกแบบ "รูปแบบ"? การออกแบบ OO เป็นสิ่งหนึ่งที่สามารถพูดได้ทั้งหมดเกี่ยวกับบริบท มันเป็นแผ่นกระดาษเปล่าขนาดใหญ่ที่ตั้งครรภ์พร้อมความเป็นไปได้

การจัดการกับรหัสที่มีอยู่เป็นบริบทที่แตกต่างกัน



ฉันกำลังทำงานกับ 'ปัญหาเดียวกันนี้ตอนนี้ ฉันกำลังแก้ไขการคัดลอกโค้ดหลายร้อยบรรทัดที่ทำไปเพื่อให้สามารถฉีดค่าได้

ทำให้รหัสเป็นโมดูลาร์

ฉันโยนรหัสซ้ำ 600 บรรทัดจากนั้นจึง refactored ดังนั้นแทนที่จะเป็น "สาย B โทร C โทร D ... " ฉันมี "โทร A, กลับ, โทร B, กลับ, โทร C ... " ทีนี้เราแค่ต้องใส่ค่าลงในหนึ่งในวิธีเหล่านั้นสมมุติว่า method E

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


ปิด

เธรดโปรแกรมเมอร์ - "เหตุใดโปรแกรมจึงใช้การปิด"

เป็นหลักคุณจะฉีดค่าลงในวิธีการที่ส่งกลับวิธีการที่กำหนดเองด้วยค่า วิธีการที่กำหนดเองนั้นจะถูกดำเนินการในภายหลัง

เทคนิคนี้จะช่วยให้คุณสามารถแก้ไขวิธีการที่มีอยู่โดยไม่ต้องเปลี่ยนลายเซ็น


วิธีการนี้ดูคุ้นเคยเป็นอย่างมาก ...

Roger ในประเด็นข้อต่อชั่วคราว (ลิงก์ของคุณ) @Snowman มันเป็นสิ่งสำคัญที่คำสั่งการดำเนินการที่จำเป็นจะถูกห่อหุ้ม
Radarbob
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.