ฉันควรใช้การพึ่งพาการฉีดหรือโรงงานคงที่?


81

เมื่อออกแบบระบบฉันมักจะประสบกับปัญหาการมีโมดูลจำนวนมาก (การบันทึก, acces ฐานข้อมูล, ฯลฯ ) ถูกใช้โดยโมดูลอื่น ๆ คำถามคือฉันจะไปเกี่ยวกับการให้ส่วนประกอบเหล่านี้กับส่วนประกอบอื่น ๆ ได้อย่างไร คำตอบสองคำตอบที่ดูเหมือนจะเป็นไปได้คือการฉีดขึ้นรูปหรือใช้รูปแบบของโรงงาน อย่างไรก็ตามทั้งคู่ดูเหมือนผิด:

  • โรงงานทำการทดสอบความเจ็บปวดและไม่อนุญาตให้สลับการใช้งานได้ง่าย พวกเขายังไม่ได้อ้างอิงที่ชัดเจน (เช่นคุณกำลังตรวจสอบวิธีการโดยไม่คำนึงถึงความจริงที่ว่ามันเรียกวิธีการที่เรียกวิธีการที่เรียกวิธีการที่ใช้ฐานข้อมูล)
  • การฉีด Dependecy จะสร้างรายการอาร์กิวเมนต์ตัวสร้างอย่างหนาแน่นและทำให้มีบางแง่มุมทั่วโค้ดของคุณ สถานการณ์ทั่วไปคือที่คอนสตรัคเตอร์ของคลาสมากกว่าครึ่งมีลักษณะเช่นนี้(....., LoggingProvider l, DbSessionProvider db, ExceptionFactory d, UserSession sess, Descriptions d)

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

ฉันจะจัดการปัญหาดังกล่าวได้อย่างไร?


2
หากโรงงานสามารถแก้ปัญหาทั้งหมดของคุณได้คุณอาจจะฉีดโรงงานเข้าไปในวัตถุของคุณและรับ LoggingProvider, DbSessionProvider, ExceptionFactory, UserSession จากนั้น
จอร์โจ

1
มี "อินพุต" มากเกินไปสำหรับวิธีหนึ่ง ๆ ไม่ว่าจะผ่านหรือฉีดเป็นปัญหาของวิธีการออกแบบเอง ไม่ว่าคุณจะไปที่ไหนด้วยคุณอาจต้องการลดขนาดวิธีการของคุณลงเล็กน้อย (ซึ่งง่ายกว่าที่จะทำเมื่อคุณฉีดเข้าที่)
Bill K

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

คำตอบ:


74

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

ตัวอย่างเช่นคุณสามารถนำรูปแบบใหม่SessionEnvironmentห่อหุ้มเซลล์แสงอาทิตย์DBSessionProviderที่และโหลดUserSession Descriptionsหากต้องการทราบว่า abstractions ใดที่สมเหตุสมผลที่สุดเราต้องทราบรายละเอียดของโปรแกรมของคุณ

คำถามที่คล้ายกันก็ถามว่าแล้วที่นี่ใน SO


9
+1: ฉันคิดว่าการจัดกลุ่มข้อโต้แย้งคอนสตรัคเตอร์เป็นคลาสเป็นความคิดที่ดีมาก นอกจากนี้ยังบังคับให้คุณจัดระเบียบข้อโต้แย้งเหล่านี้เป็นโครงสร้างที่มีความหมายมากขึ้น
Giorgio

5
แต่ถ้าผลลัพธ์นั้นไม่ใช่โครงสร้างที่มีความหมายคุณก็แค่ hidding ความซับซ้อนที่ละเมิด SRP ในกรณีนี้ควรทำการปรับโครงสร้างชั้นเรียนใหม่
danidacar

1
@Giorgio ฉันไม่เห็นด้วยกับคำสั่งทั่วไปว่า "การจัดกลุ่มข้อโต้แย้งคอนสตรัคเตอร์เป็นคลาสเป็นความคิดที่ดีมาก" หากคุณมีคุณสมบัตินี้ด้วย "ในสถานการณ์นี้" มันแตกต่างกัน
tymtam

19

การฉีด Dependecy จะสร้างรายการอาร์กิวเมนต์ตัวสร้างอย่างหนาแน่นและทำให้มีบางแง่มุมทั่วโค้ดของคุณ

จากนั้นดูเหมือนคุณจะไม่เข้าใจ DI ที่เหมาะสม - ความคิดคือการกลับรูปแบบการสร้างอินสแตนซ์วัตถุภายในโรงงาน

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

อีกวิธีคือการมีโรงงานยกเว้นซึ่งถูกส่งผ่านไปยังวัตถุผ่านทางตัวสร้าง แทนการขว้างปาข้อยกเว้นใหม่ชั้นสามารถโยนกับวิธีการของโรงงาน throw PrettyExceptionFactory.createException(data)(เช่น

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


1
ฉันได้อ่านที่ไหนสักแห่งว่าเมื่อรายการพารามิเตอร์ของคุณยาวเกินไปไม่ใช่เพราะคุณใช้การฉีดแบบพึ่งพา แต่เพราะคุณต้องการการฉีดแบบพึ่งพามากขึ้น
จอร์โจ

นั่นอาจเป็นหนึ่งในเหตุผล - โดยทั่วไปขึ้นอยู่กับภาษาคอนสตรัคเตอร์ของคุณควรมีอาร์กิวเมนต์ไม่เกิน 6-8 ข้อและไม่เกิน 3-4 ข้อควรเป็นวัตถุเองยกเว้นรูปแบบเฉพาะ (เช่นBuilderรูปแบบ) กำหนดมัน หากคุณส่งพารามิเตอร์ไปยังตัวสร้างของคุณเนื่องจากวัตถุของคุณทำให้วัตถุอื่น ๆ นั้นเป็นแบบ instantiates นั่นเป็นกรณีที่ชัดเจนสำหรับ IoC
Jonathan Rich

12

คุณได้ระบุข้อเสียของรูปแบบสแตติกจากโรงงานค่อนข้างดี แต่ฉันไม่เห็นด้วยกับข้อเสียของรูปแบบการฉีดพึ่งพา:

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

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

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

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

ด้วยวิธีนี้คุณสามารถลบการขึ้นต่อกันที่ไม่จำเป็น 3 รายการ (UserSession, ExceptionFactory และอาจมีคำอธิบาย) จึงทำให้รหัสของคุณง่ายขึ้นและหลากหลายยิ่งขึ้น

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


นี้. ฉันไม่สามารถเห็นความจำเป็นที่จะตีฐานข้อมูลเพื่อโยนข้อยกเว้น
Caleth

1

ใช้การฉีดพึ่งพา การใช้โรงงานแบบคงที่เป็นการจ้างงานของService Locatorปฏิปักษ์ ดูงานน้ำเชื้อจาก Martin Fowler ได้ที่นี่ - http://martinfowler.com/articles/inject.html

หากข้อโต้แย้งคอนสตรัคเตอร์ของคุณใหญ่เกินไปและคุณไม่ได้ใช้คอนเทนเนอร์ DI หมายความว่าให้เขียนโรงงานของคุณสำหรับการสร้างอินสแตนซ์อนุญาตให้กำหนดค่าได้ไม่ว่าจะโดย XML หรือการเชื่อมโยงการนำไปใช้กับอินเทอร์เฟซ


5
ตัวระบุบริการไม่ได้เป็น antipattern - ฟาวเลอร์เองอ้างถึงใน URL ที่คุณโพสต์ ในขณะที่รูปแบบของตัวค้นหาผู้ให้บริการสามารถถูกใช้งานในทางเดียวกัน (เช่นเดียวกับที่ใช้ในทางที่ผิดเพื่อแยกรัฐออกไป) แต่เป็นรูปแบบที่มีประโยชน์มาก
Jonathan Rich

1
น่าสนใจน่ารู้ ฉันเคยได้ยินมันเรียกว่ารูปแบบการต่อต้าน
Sam

4
มันเป็นเพียงปฏิปักษ์ถ้าตัวระบุบริการถูกใช้เพื่อจัดเก็บสถานะส่วนกลาง ตัวระบุตำแหน่งบริการควรเป็นวัตถุไร้สัญชาติหลังจากเริ่มต้นและไม่เปลี่ยนรูป
Jonathan Rich

XML พิมพ์ไม่ปลอดภัย ฉันจะพิจารณาว่าเป็นแผน z หลังจากแนวทางอื่น ๆ ล้มเหลว
Richard Tingle

1

ฉันจะไปด้วยกันกับการฉีดพึ่งพา โปรดจำไว้ว่า DI ไม่เพียงทำผ่านตัวสร้างเท่านั้น แต่ยังผ่านตัวตั้งค่าคุณสมบัติด้วย ตัวอย่างเช่นตัวบันทึกอาจถูกฉีดเป็นคุณสมบัติ

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

ขั้นตอนต่อไปที่คุณอาจต้องการคือ Programmnig ที่เน้นการใช้งานซึ่งถูกนำไปใช้ในกรอบงานหลัก ๆ สิ่งนี้ช่วยให้คุณสามารถดักจับ (หรือ "แนะนำ" เพื่อใช้คำศัพท์ AspectJ) ตัวสร้างของคลาสและฉีดคุณสมบัติที่เกี่ยวข้องอาจได้รับคุณสมบัติพิเศษ


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

1
DI ผ่านตัวตั้งค่าคุณสมบัติเหมาะอย่างยิ่งสำหรับการอ้างอิงเพิ่มเติม การบันทึกเป็นตัวอย่างที่ดี ถ้าคุณต้องการการบันทึกจากนั้นตั้งค่าคุณสมบัติตัวบันทึกถ้าไม่ทำอย่าตั้งค่า
เพรสตัน

1

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

ฉันไม่ค่อยเห็นด้วย อย่างน้อยก็ไม่ได้โดยทั่วไป

โรงงานที่เรียบง่าย:

public IFoo GetIFoo()
{
    return new Foo();
}

ฉีดง่าย:

myDependencyInjector.Bind<IFoo>().To<Foo>();

ทั้งสองตัวอย่างวัตถุประสงค์เดียวกันพวกเขาตั้งค่าการเชื่อมโยงระหว่างและIFoo Fooทุกอย่างอื่นเป็นเพียงไวยากรณ์

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

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


การฉีด Dependecy จะสร้างรายการอาร์กิวเมนต์ตัวสร้างอย่างหนาแน่นและทำให้มีบางแง่มุมทั่วโค้ดของคุณ

นี่คือเหตุผลที่บางคนชอบที่จะดึงการอ้างอิงในตัวสร้างอย่างชัดเจนเช่นนี้:

public MyService()
{
    _myFoo = DependencyFramework.Get<IFoo>();
}

ฉันเคยได้ยินข้อโต้แย้งมืออาชีพ (ไม่มีตัวสร้างบวม) ฉันเคยได้ยินข้อโต้แย้งแย้ง (การใช้ตัวสร้างช่วยให้ DI อัตโนมัติมากขึ้น)

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

ในระดับเทคนิคฉันไม่สนใจวิธีใด ตัวเลือกทั้งสองใช้ความพยายามมากในการพิมพ์ และเนื่องจากคุณใช้ DI คุณจะไม่เรียกตัวสร้างด้วยตนเองเลย แต่ข้อผิดพลาด Visual Studio UI ทำให้ฉันชอบไม่ bloating อาร์กิวเมนต์ตัวสร้าง


ตามบันทึกข้าง, ฉีดพึ่งพาและโรงงานไม่ได้พิเศษร่วมกัน ฉันมีกรณีที่แทนที่จะแทรกการพึ่งพาฉันได้แทรกโรงงานที่สร้างการอ้างอิง (โชคดีที่อนุญาตให้คุณใช้Func<IFoo>เพื่อให้คุณไม่ต้องสร้างคลาสโรงงานจริง)

กรณีการใช้งานสำหรับสิ่งนี้มีน้อยมาก แต่มีอยู่จริง


OP ถามเกี่ยวกับโรงงานคงที่ stackoverflow.com/questions/929021/…
Basilevs

@Basilevs "คำถามคือฉันจะให้ส่วนประกอบเหล่านี้กับส่วนประกอบอื่น ๆ ได้อย่างไร"
Anthony Rutledge

1
@Basilevs ทุกอย่างที่ฉันพูดนอกเหนือจากบันทึกด้านข้างจะใช้กับโรงงานแบบคงที่เช่นกัน ฉันไม่แน่ใจว่าคุณกำลังพยายามชี้เฉพาะ ลิงค์อ้างอิงถึงอะไร
Flater

กรณีการใช้งานอย่างใดอย่างหนึ่งในการฉีดโรงงานเป็นกรณีที่มีการกำหนดคลาสคำขอ HTTP ที่เป็นนามธรรมและวางแผนคลาสย่อย polymorphic อีกห้าคลาสสำหรับ GET, POST, PUT, PATCH และ DELETE? คุณไม่สามารถรู้ได้ว่าจะใช้วิธี HTTP ใดในแต่ละครั้งเมื่อพยายามรวมลำดับชั้นของคลาสดังกล่าวเข้ากับเราเตอร์ประเภท MVC (ซึ่งอาจอาศัยส่วนหนึ่งของคลาสคำขอ HTTP) ส่วนต่อประสานข้อความ HTTP PSR-7 นั้นน่าเกลียด
Anthony Rutledge

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

0

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

<?php
namespace TFWD\Factories;

/**
 * A class responsible for instantiating
 * InboundHttpRequest objects (PHP 7.x)
 * 
 * @author Anthony E. Rutledge
 * @version 2.0
 */
class InboundHttpRequestFactory 
{
    private const GET = 'GET';
    private const POST = 'POST';
    private const PUT = 'PUT';
    private const PATCH = 'PATCH';
    private const DELETE = 'DELETE';

    private static $di;
    private static $method;

    // public function __construct(Injector $di, Validator $httpRequestValidator)
    // {
    //    $this->di = $di;
    //    $this->method = $httpRequestValidator->getMethod();
    // }

    public static function setInjector(Injector $di)
    {
        self::$di = $di;
    }    

    public static setMethod(string $method)
    {
        self::$method = $method;
    }

    public static function getRequest()
    {
        if (self::$method == self::GET) {
            return self::$di->get('InboundGetHttpRequest');
        } elseif ((self::$method == self::POST) && empty($_FILES)) {
            return self::$di->get('InboundPostHttpRequest');
        } elseif (self::$method == self::POST) {
            return self::$di->get('InboundFilePostHttpRequest');
        } elseif (self::$method == self::PUT) {
            return self::$di->get('InboundPutHttpRequest');
        } elseif (self::$method == self::PATCH) {
            return self::$di->get('InboundPatchHttpRequest');
        } elseif (self::$method == self::DELETE) {
            return self::$di->get('InboundDeleteHttpRequest');
        } else {
            throw new \RuntimeException("Unexpected HTTP request. Invalid request.");
        }
    }
}

รหัสลูกค้าสำหรับการตั้งค่าประเภท MVC ภายในส่วนกลางindex.phpอาจมีลักษณะดังต่อไปนี้ (ละเว้นการตรวจสอบ)

InboundHttpRequestFactory::setInjector($di);
InboundHttpRequestFactory::setMethod($httpRequestValidator->getMethod());
$di->set('InboundHttpRequest', InboundHttpRequestFactory::getRequest());
$router = $di->get('Router');  // The Router class depends on InboundHttpRequest objects.
$router->dispatch(); 

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


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