ประโยชน์ของการฉีดแบบพึ่งพามีอะไรบ้าง?


104

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

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

เมื่อเทียบกับรหัสจาวาเก่าธรรมดาเช่น:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

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


UPDATE:
ในกรณีของ

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

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

มันน่าสนใจมากที่ได้เห็นส่วนกำหนดค่าเล็ก ๆ สำหรับ IoC ซึ่งแสดงให้เห็นถึงประโยชน์ของมัน ฉันใช้ Spring มาระยะหนึ่งแล้วและไม่สามารถยกตัวอย่างเช่นนี้ได้ และฉันสามารถแสดงบรรทัดเดียวซึ่งแสดงให้เห็นถึงประโยชน์ของ hibernate, dwr และเฟรมเวิร์กอื่น ๆ ที่ฉันใช้


อัปเดต 2:
ฉันทราบว่าการกำหนดค่า IoC สามารถเปลี่ยนแปลงได้โดยไม่ต้องคอมไพล์ใหม่ มันเป็นความคิดที่ดีจริงๆหรือ? ฉันเข้าใจได้เมื่อมีคนต้องการเปลี่ยนข้อมูลรับรอง DB โดยไม่ต้องคอมไพล์ใหม่ - เขาอาจไม่ใช่ผู้พัฒนา ในทางปฏิบัติของคุณคนอื่นที่ไม่ใช่นักพัฒนาเปลี่ยนแปลงการกำหนดค่า IoC บ่อยเพียงใด ฉันคิดว่าสำหรับนักพัฒนาไม่มีความพยายามที่จะคอมไพล์คลาสนั้นซ้ำแทนที่จะเปลี่ยนการกำหนดค่า และสำหรับผู้ที่ไม่ใช่นักพัฒนาคุณอาจต้องการทำให้ชีวิตของเขาง่ายขึ้นและมีไฟล์กำหนดค่าที่ง่ายกว่านี้


อัปเดต 3:

การกำหนดค่าภายนอกของการทำแผนที่ระหว่างอินเทอร์เฟซและการใช้งานคอนกรีต

อะไรคือสิ่งที่ดีในการทำให้มันขยายออกไป? คุณไม่ได้ทำให้โค้ดทั้งหมดของคุณเป็นภายนอกในขณะที่คุณทำได้อย่างแน่นอน - เพียงแค่วางไว้ในไฟล์ ClassName.java.txt อ่านและคอมไพล์ด้วยตนเองทันที - ว้าวคุณหลีกเลี่ยงการคอมไพล์ซ้ำ ทำไมต้องคอมไพล์?!

คุณประหยัดเวลาในการเข้ารหัสเนื่องจากคุณระบุการแมปอย่างเปิดเผยไม่ใช่ในรหัสขั้นตอน

ฉันเข้าใจว่าบางครั้งวิธีการที่เปิดเผยจะช่วยประหยัดเวลา ตัวอย่างเช่นฉันประกาศเพียงครั้งเดียวการแมประหว่างคุณสมบัติ bean กับคอลัมน์ DB และไฮเบอร์เนตใช้การแมปนี้ในขณะโหลดบันทึกสร้าง SQL ตาม HSQL เป็นต้นนี่คือที่ที่วิธีการประกาศทำงาน ในกรณีของ Spring (ในตัวอย่างของฉัน) การประกาศมีจำนวนบรรทัดมากกว่าและมีการแสดงออกเช่นเดียวกับรหัสที่เกี่ยวข้อง หากมีตัวอย่างเมื่อการประกาศดังกล่าวสั้นกว่ารหัส - ฉันต้องการดู

หลักการ Inversion of Control ช่วยให้สามารถทดสอบหน่วยได้ง่ายเพราะคุณสามารถแทนที่การใช้งานจริงด้วยของปลอมได้ (เช่นการแทนที่ฐานข้อมูล SQL ด้วยในหน่วยความจำ)

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

mary = new FakeFemale();

ฉันเข้าใจประโยชน์ของ DI ฉันไม่เข้าใจว่าการกำหนดค่า XML ภายนอกเพิ่มประโยชน์อะไรบ้างเมื่อเทียบกับการกำหนดค่าโค้ดที่ทำเหมือนกัน ฉันไม่คิดว่าควรหลีกเลี่ยงการรวบรวม - ฉันรวบรวมทุกวันและฉันยังมีชีวิตอยู่ ฉันคิดว่าการกำหนดค่า DI เป็นตัวอย่างที่ไม่ดีของวิธีการที่เปิดเผย การประกาศจะมีประโยชน์หากมีการประกาศครั้งเดียวและใช้หลายครั้งในรูปแบบต่างๆเช่น hibernate cfg ที่การแม็ประหว่างคุณสมบัติ bean และคอลัมน์ DB ใช้สำหรับบันทึกโหลดสร้างคิวรีการค้นหา ฯลฯ การกำหนดค่า Spring DI สามารถแปลเป็น configuring code เหมือนในตอนต้นของคำถามนี้ได้หรือไม่? และใช้สำหรับการเริ่มต้นถั่วเท่านั้นไม่ใช่หรือ? ซึ่งหมายความว่าวิธีการที่เปิดเผยไม่ได้เพิ่มอะไรที่นี่ใช่หรือไม่?

เมื่อฉันประกาศการทำแผนที่ไฮเบอร์เนตฉันแค่ให้ข้อมูลบางอย่างในโหมดไฮเบอร์เนตและมันก็ใช้งานได้ - ฉันไม่ได้บอกว่าต้องทำอะไร ในกรณีของฤดูใบไม้ผลิคำประกาศของฉันบอกให้สปริงต้องทำอย่างแน่นอน - ทำไมต้องประกาศทำไมไม่ทำ


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


21
ในที่สุดก็มีคนกล้าถามคำถามนี้ เหตุใดคุณจึงต้องการหลีกเลี่ยงการคอมไพล์ซ้ำเมื่อการใช้งานของคุณเปลี่ยนไปโดยเสียค่าใช้จ่ายในการเสียสละ (หรืออย่างน้อยก็ลดระดับ) การสนับสนุนเครื่องมือ / IDE
Christian Klauser

3
ดูเหมือนชื่อเรื่องจะไม่ค่อยถูกต้องนัก ผู้เขียนได้กล่าวว่าคอนเทนเนอร์ IOC นั้นใช้ได้ แต่ดูเหมือนว่าจะมีปัญหากับการใช้การกำหนดค่า XML แทนที่จะกำหนดค่าผ่านรหัส (และยุติธรรมมากพอด้วย) ฉันขอแนะนำว่า "ประโยชน์ของการกำหนดค่าคอนเทนเนอร์ IOC ผ่าน XML หรือวิธีการอื่น ๆ ที่ไม่ใช่รหัสมีอะไรบ้าง"
Orion Edwards

@ Orion ตัวอย่างที่ฉันให้ไว้ (พร้อมชายและหญิง) ไม่ต้องการคอนเทนเนอร์ IOC ใด ๆ ฉันสบายดีกับ IOC การใช้คอนเทนเนอร์ไม่ว่าจะกำหนดค่าโดยใช้ XML หรือไม่ก็ยังคงเป็นคำถามที่เปิดกว้างสำหรับฉัน
Pavel Feldman

@Orion 2: แม้ว่าฉันจะใช้ IOC บางรูปแบบในโครงการส่วนใหญ่ แต่บางส่วนก็ได้รับประโยชน์จากคอนเทนเนอร์ IOC มากพอ ๆ กับที่พวกเขาได้รับประโยชน์จาก Variable Assignment Container หรือ If Statement Container แต่ภาษาก็เพียงพอแล้วสำหรับฉัน ฉันไม่มีปัญหาในการคอมไพล์โครงการใหม่ที่ฉันกำลังดำเนินการและมีการแยกโค้ดเริ่มต้น dev / test / production ออกจากกันอย่างสะดวก สำหรับฉันชื่อเรื่องก็โอเค
Pavel Feldman

ฉันเห็นปัญหากับตัวอย่าง ตามหลักการคือบริการ Inject ไม่ใช่ข้อมูล
Jacek Cz

คำตอบ:


40

สำหรับตัวฉันเองหนึ่งในเหตุผลหลักในการใช้ IoC (และใช้ประโยชน์จากการกำหนดค่าภายนอก) อยู่รอบ ๆ สองส่วนของ:

  • การทดสอบ
  • การบำรุงรักษาการผลิต

การทดสอบ

หากคุณแบ่งการทดสอบออกเป็น 3 สถานการณ์ (ซึ่งค่อนข้างปกติในการพัฒนาขนาดใหญ่):

  1. การทดสอบหน่วย
  2. การทดสอบการผสานรวม
  3. การทดสอบกล่องดำ

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

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

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

การผลิต

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

สรุป

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

  • มีการแจกจ่ายแอปพลิเคชันไปยังไซต์ / ไคลเอนต์หลายแห่งซึ่งสภาพแวดล้อมจะแตกต่างกัน
  • การควบคุม / ป้อนข้อมูลการพัฒนาที่ จำกัด ในสภาพแวดล้อมการผลิตและการตั้งค่า
  • สถานการณ์การทดสอบ

ในทางปฏิบัติฉันพบว่าแม้ว่าจะพัฒนาบางสิ่งที่คุณสามารถควบคุมสภาพแวดล้อมได้ แต่ก็จะทำงานต่อไป แต่เมื่อเวลาผ่านไปมันจะเป็นการดีกว่าที่จะให้คนอื่นมีความสามารถในการเปลี่ยนแปลงการกำหนดค่า:

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

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


14

Dependency injection เป็นรูปแบบการเข้ารหัสที่มีรากฐานมาจากการสังเกตว่าการมอบหมายวัตถุมักจะเป็นรูปแบบการออกแบบที่มีประโยชน์มากกว่าการสืบทอดวัตถุ (กล่าวคือความสัมพันธ์ของวัตถุมีประโยชน์มากกว่าความสัมพันธ์ของวัตถุ) ส่วนประกอบอื่น ๆ มีความจำเป็นอย่างไรก็ตามเพื่อให้ DI ทำงานได้นั่นคือการสร้างอินเทอร์เฟซของอ็อบเจ็กต์ การรวมกันของวิศวกรซอฟต์แวร์รูปแบบการออกแบบที่ทรงพลังทั้งสองนี้ตระหนักได้อย่างรวดเร็วว่าพวกเขาสามารถสร้างโค้ดคู่แบบหลวม ๆ ที่ยืดหยุ่นได้จึงเกิดแนวคิดของ Dependency Injection อย่างไรก็ตามมันไม่ได้จนกว่าการสะท้อนของวัตถุจะพร้อมใช้งานในภาษาระดับสูงบางภาษาที่ DI นำออกไปจริงๆ องค์ประกอบการสะท้อนเป็นหัวใจหลักของทุกวันนี้ '

ภาษาต้องให้การสนับสนุนที่ดีสำหรับทั้งเทคนิคการเขียนโปรแกรมเชิงวัตถุแบบปกติรวมถึงการสนับสนุนอินเทอร์เฟซอ็อบเจ็กต์และการสะท้อนวัตถุ (เช่น Java และ C #) ในขณะที่คุณสามารถสร้างโปรแกรมโดยใช้รูปแบบ DI ในระบบ C ++ แต่การขาดการสนับสนุนการสะท้อนภายในภาษาที่เหมาะสมทำให้ไม่สนับสนุนแอปพลิเคชันเซิร์ฟเวอร์และแพลตฟอร์ม DI อื่น ๆ และด้วยเหตุนี้จึง จำกัด การแสดงออกของรูปแบบ DI

จุดแข็งของระบบที่สร้างโดยใช้รูปแบบ DI:

  1. รหัส DI นั้นง่ายกว่ามากที่จะนำมาใช้ซ้ำเนื่องจากฟังก์ชัน 'ขึ้นอยู่กับ' ถูกคาดการณ์ไว้ในอินเทอร์เฟซที่กำหนดไว้อย่างดีทำให้สามารถแยกวัตถุที่มีการกำหนดค่าได้รับการจัดการโดยแพลตฟอร์มแอปพลิเคชันที่เหมาะสมเพื่อเสียบเข้ากับวัตถุอื่น ๆ ตามต้องการ
  2. รหัส DI นั้นทดสอบได้ง่ายกว่ามาก ฟังก์ชันที่แสดงโดยอ็อบเจ็กต์สามารถทดสอบได้ในกล่องดำโดยการสร้างอ็อบเจกต์ 'จำลอง' โดยใช้อินเทอร์เฟซที่คาดหวังโดยตรรกะของแอปพลิเคชันของคุณ
  3. รหัส DI มีความยืดหยุ่นมากขึ้น มันเป็นรหัสที่คู่กันอย่างหลวม ๆ - ถึงมาก สิ่งนี้ช่วยให้โปรแกรมเมอร์สามารถเลือกและเลือกวิธีที่จะเชื่อมต่อออบเจ็กต์โดยพิจารณาจากอินเทอร์เฟซที่ต้องการบนปลายด้านหนึ่งและอินเทอร์เฟซที่แสดงบนอีกด้านหนึ่ง
  4. การกำหนดค่าภายนอก (Xml) ของวัตถุ DI หมายความว่าผู้อื่นสามารถปรับแต่งโค้ดของคุณในทิศทางที่ไม่คาดคิดได้
  5. นอกจากนี้การกำหนดค่าภายนอกยังเป็นการแยกรูปแบบความกังวลซึ่งปัญหาทั้งหมดของการเริ่มต้นอ็อบเจ็กต์และการจัดการการพึ่งพาระหว่างกันของอ็อบเจ็กต์สามารถจัดการได้โดยแอ็พพลิเคชันเซิร์ฟเวอร์
  6. โปรดทราบว่าการกำหนดค่าภายนอกไม่จำเป็นต้องใช้รูปแบบ DI สำหรับการเชื่อมต่อระหว่างกันอย่างง่ายอ็อบเจ็กต์ตัวสร้างขนาดเล็กมักจะเพียงพอ มีข้อแลกเปลี่ยนในความยืดหยุ่นระหว่างทั้งสอง อ็อบเจ็กต์ตัวสร้างไม่มีตัวเลือกที่ยืดหยุ่นเท่ากับไฟล์คอนฟิกูเรชันที่มองเห็นได้จากภายนอก ผู้พัฒนาระบบ DI จะต้องชั่งน้ำหนักข้อดีของความยืดหยุ่นมากกว่าความสะดวกสบายการดูแลว่าขนาดเล็กการควบคุมเกรนละเอียดสำหรับโครงสร้างวัตถุตามที่แสดงในไฟล์การกำหนดค่าอาจเพิ่มความสับสนและค่าใช้จ่ายในการบำรุงรักษาตามลำดับ

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

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

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

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


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

> การกำหนดค่าภายนอกก็เป็นการแยก ... การแยกส่วนกำหนดค่าถือเป็นหัวใจของ DI ซึ่งถือเป็นเรื่องดี และสามารถ de Dome โดยใช้รหัสเริ่มต้น cfg เพิ่มอะไรเมื่อเทียบกับรหัสเริ่มต้น? สำหรับฉันดูเหมือนว่า cfg แต่ละบรรทัดจะมีบรรทัดรหัสเริ่มต้นที่ตรงกัน
Pavel Feldman

7

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

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

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

อย่างไรก็ตามการกำหนดค่า XML เป็นเรื่องเล็กน้อยของสัตว์เลี้ยงของฉัน ... ฉันพยายามหลีกเลี่ยงค่าใช้จ่ายทั้งหมด


5

เมื่อใดก็ตามที่คุณสามารถเปลี่ยนรหัสของคุณเป็นข้อมูลคุณกำลังดำเนินการไปในทิศทางที่ถูกต้อง

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

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

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


เข้าท่าไม่ได้คิดเกี่ยวกับเรื่องนี้ในมุมมองนี้
Pavel Feldman

7
จากนั้นอีกครั้งผู้คนมักจะไปทางอื่นและลองใส่ตรรกะลงในข้อมูลซึ่งหมายความว่าคุณจะลงท้ายด้วยการเข้ารหัสแอปพลิเคชันของคุณในภาษาโปรแกรมที่ไม่ได้มาตรฐาน
Casebash

@Casebash นั่นเป็นมุมมองที่น่าสนใจ - ฉันสนใจตัวอย่างมาก ฉันพบว่าทุกสิ่งที่ฉันสามารถย้ายเข้าไปในข้อมูลช่วยได้ ฉันยังพบว่าถ้าฉันทำตามที่คุณกำลังพูดภาษาจะดีขึ้นจริงเพราะเป็น DSL - แต่ถึงอย่างนั้นก็ต้องใช้เหตุผลอย่างจริงจังในการสร้างภาษาใหม่ทั้งหมด
Bill K

1
"เมื่อใดก็ตามที่คุณสามารถเปลี่ยนรหัสของคุณเป็นข้อมูลที่คุณกำลังดำเนินการไปในทิศทางที่ถูกต้อง" ยินดีต้อนรับสู่รูปแบบการต่อต้าน Soft Coding
Raedwald

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

3

เหตุผลในการใช้คอนเทนเนอร์ DI คือคุณไม่จำเป็นต้องมีพร็อพเพอร์ตี้พันล้านรายการที่กำหนดค่าไว้ล่วงหน้าในโค้ดของคุณซึ่งเป็นเพียงแค่ getters และ setters คุณต้องการฮาร์ดโค้ดทั้งหมดด้วย X () ใหม่หรือไม่? แน่นอนว่าคุณสามารถมีค่าเริ่มต้นได้ แต่คอนเทนเนอร์ DI อนุญาตให้สร้าง singletons ซึ่งง่ายมากและช่วยให้คุณมุ่งเน้นไปที่รายละเอียดของรหัสไม่ใช่งานเบ็ดเตล็ดในการเริ่มต้น

ตัวอย่างเช่น Spring อนุญาตให้คุณใช้อินเทอร์เฟซ InitializingBean และเพิ่มเมธอด afterPropertiesSet (คุณอาจระบุ "init-method" เพื่อหลีกเลี่ยงการเชื่อมต่อโค้ดของคุณกับ Spring) วิธีการเหล่านี้จะช่วยให้คุณมั่นใจได้ว่าอินเทอร์เฟซใด ๆ ที่ระบุเป็นฟิลด์ในอินสแตนซ์คลาสของคุณได้รับการกำหนดค่าอย่างถูกต้องเมื่อเริ่มต้นระบบจากนั้นคุณไม่จำเป็นต้องตรวจสอบตัวรับและตัวตั้งค่าเป็นโมฆะอีกต่อไป (สมมติว่าคุณอนุญาตให้ singletons ของคุณยังคงปลอดภัยเธรด ).

นอกจากนี้การเริ่มต้นที่ซับซ้อนด้วยคอนเทนเนอร์ DI นั้นง่ายกว่ามากแทนที่จะทำด้วยตัวเอง ตัวอย่างเช่นฉันช่วยในการใช้ XFire (ไม่ใช่ CeltiXFire เราใช้เฉพาะ Java 1.4) แอปใช้ Spring แต่น่าเสียดายที่ใช้กลไกการกำหนดค่า services.xml ของ XFire เมื่อจำเป็นต้องมีการรวบรวมองค์ประกอบเพื่อประกาศว่ามีอินสแตนซ์เป็นศูนย์หรือมากกว่าแทนที่จะเป็นหนึ่งอินสแตนซ์หรือมากกว่านั้นฉันต้องแทนที่โค้ด XFire ที่ให้ไว้สำหรับบริการนี้โดยเฉพาะ

มีค่าเริ่มต้นของ XFire ที่กำหนดไว้ในสคีมาถั่วสปริง ดังนั้นหากเราใช้ Spring เพื่อกำหนดค่าบริการอาจใช้ถั่วได้ สิ่งที่เกิดขึ้นคือฉันต้องจัดหาอินสแตนซ์ของคลาสเฉพาะในไฟล์ services.xml แทนการใช้ bean ในการทำเช่นนี้ฉันต้องจัดเตรียมตัวสร้างและตั้งค่าการอ้างอิงที่ประกาศในการกำหนดค่า XFire การเปลี่ยนแปลงที่แท้จริงที่ฉันต้องทำทำให้ฉันต้องโอเวอร์คลาสเดียว

แต่ด้วยไฟล์ services.xml ฉันต้องสร้างคลาสใหม่สี่คลาสโดยตั้งค่าดีฟอลต์ตามค่าดีฟอลต์ในไฟล์คอนฟิกูเรชัน Spring ในคอนสตรัคเตอร์ หากเราสามารถใช้การกำหนดค่า Spring ได้ฉันสามารถระบุได้ว่า:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

แต่ดูเหมือนมากกว่านี้:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

ดังนั้นผลลัพธ์สุทธิคือต้องเพิ่มคลาส Java เพิ่มเติมสี่คลาสที่ไม่มีจุดหมายส่วนใหญ่ไปยังโค้ดเบสเพื่อให้ได้ผลกระทบจากคลาสเพิ่มเติมหนึ่งคลาสและข้อมูลคอนเทนเนอร์ที่อ้างอิงง่าย ๆ นี่ไม่ใช่ "ข้อยกเว้นที่พิสูจน์กฎ" นี่คือกฎ ... การจัดการนิสัยแปลก ๆ ในโค้ดจะสะอาดกว่ามากเมื่อคุณสมบัตินั้นถูกจัดเตรียมไว้แล้วในคอนเทนเนอร์ DI และคุณเพียงแค่เปลี่ยนให้เหมาะกับสถานการณ์พิเศษ ซึ่งเกิดขึ้นบ่อยกว่าไม่มาก


3

ฉันมีคำตอบของคุณ

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

กรณีการใช้งานที่เป็นประโยชน์อื่น ๆ เกี่ยวกับระบบการสร้างและการกำหนดค่าภายนอก:

  • การฉีดสไตล์ / สไตล์ชีตสำหรับฐานรหัสเดียวสำหรับงานสร้างที่แตกต่างกัน
  • การฉีดชุดเนื้อหาไดนามิกที่แตกต่างกัน (หรือการอ้างอิงถึง) สำหรับฐานรหัสเดียวของคุณ
  • การฉีดบริบทโลคัลไลเซชันสำหรับบิลด์ / ไคลเอ็นต์ที่แตกต่างกัน
  • การเปลี่ยน URI บริการเว็บเป็นเซิร์ฟเวอร์สำรอง (เมื่อเซิร์ฟเวอร์หลักหยุดทำงาน)

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

  • ลองนึกภาพคุณมีระบบที่คอยตรวจสอบการเข้าชมเว็บไซต์ของคุณ ขึ้นอยู่กับ # ของผู้ใช้พร้อมกันมันจะเปิด / ปิดกลไกการบันทึก บางทีในขณะที่กลไกปิดอยู่จะมีการวางวัตถุต้นขั้วเข้าที่
  • ลองนึกภาพคุณมีระบบการประชุมทางเว็บซึ่งขึ้นอยู่กับจำนวนผู้ใช้คุณต้องการเปลี่ยนความสามารถในการทำ P2P โดยขึ้นอยู่กับจำนวนผู้เข้าร่วม

+1 สำหรับการเน้นด้านองค์กรที่ด้านบน การทดสอบรหัสเดิมที่เขียนไม่ดีอาจเป็นฝันร้ายตลอดทั้งวันในบางครั้ง
Richard Le Mesurier

2

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


การปรับใช้? น่าจะเป็น ... การบำรุงรักษาการใช้งาน? น่าจะเป็น ... การบำรุงรักษารหัส? ฉันมักจะคิดว่าไม่ ... การดีบักผ่านเฟรมเวิร์กมีแนวโน้มที่จะปวดหัวมากและ pojos ก็จัดการได้ง่ายกว่ามากในเรื่องนั้น
Mike Stone

1
ไมค์ฉันไม่ได้พูดอะไรเกี่ยวกับรหัส เราทุกคนรู้ดีว่าการกำหนดค่า XML นั้นแย่ :)
aku

อืม .. คุณเปลี่ยนส่วนประกอบโดยไม่ต้องคอมไพล์ใหม่บ่อยแค่ไหนและเพื่ออะไร? ฉันเข้าใจว่ามีคนเปลี่ยนข้อมูลรับรอง DB และไม่ต้องการคอมไพล์โปรแกรมใหม่ - เขาอาจไม่ใช่คนที่พัฒนา แต่ฉันแทบไม่สามารถจินตนาการได้ว่ามีคนอื่นนอกจากนักพัฒนาที่เปลี่ยนการกำหนดค่าสปริง
Pavel Feldman

โดยปกติแล้ว Pavel สถานการณ์นี้จะเกิดขึ้นเมื่อคุณต้องปรับใช้โปรแกรมกับไคลเอนต์หลายร้อยราย ในสถานการณ์เช่นนี้การเปลี่ยน config จะง่ายกว่าการปรับใช้ผลิตภัณฑ์เวอร์ชันใหม่ คุณพูดถูกเกี่ยวกับ devs โดยปกตินักพัฒนาจะสร้าง cfg ใหม่และผู้ดูแลระบบจะปรับใช้
aku

2

คุณสามารถใช้งานใหม่สำหรับแฟนได้ ดังนั้นจึงสามารถฉีดผู้หญิงใหม่ได้โดยไม่ต้องคอมไพล์โค้ดของคุณใหม่

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(ด้านบนถือว่าหญิงและหญิงฮอตใช้อินเทอร์เฟซ GirlfFriend เดียวกัน)


เหตุใดการปรับเปลี่ยนตรรกะโดยไม่ต้องคอมไพล์ใหม่จึงถือเป็นความคิดที่ดี
Pavel Feldman

ฉันทำได้แน่นอน HotFemale jane = HotFmale ใหม่ (); jane.setAge (19); john.setGirlfriend (เจน); ดังนั้นข้อแตกต่างเพียงอย่างเดียวคือ cfg สามารถเปลี่ยนแปลงได้โดยไม่ต้องคอมไพล์ใหม่? ดูเหมือนจะเป็นคำตอบทั่วไปเมื่อพูดถึงฤดูใบไม้ผลิ ทำไม?! เหตุใดจึงควรหลีกเลี่ยงการคอมไพล์
Pavel Feldman

ฉันสามารถทดสอบโค้ดได้ดีขึ้นฉันสามารถ Mock the Female Object ได้
Paul Whelan

@Pavel Feldman: เพราะถ้าคุณมีแอพที่ติดตั้งที่ไคลเอนต์อยู่แล้วจะง่ายกว่า
Andrei Rînea

1

ในโลก. NET เฟรมเวิร์ก IoC ส่วนใหญ่มีทั้งการกำหนดค่า XML และ Code

StructureMap และ Ninject เช่นใช้อินเทอร์เฟซที่คล่องแคล่วเพื่อกำหนดค่าคอนเทนเนอร์ คุณไม่ถูก จำกัด ให้ใช้ไฟล์คอนฟิกูเรชัน XML อีกต่อไป Spring ซึ่งมีอยู่ใน. NET นั้นอาศัยไฟล์ XML เป็นอย่างมากเนื่องจากเป็นอินเทอร์เฟซการกำหนดค่าหลักในอดีต แต่ยังคงเป็นไปได้ที่จะกำหนดค่าคอนเทนเนอร์โดยใช้โปรแกรม


มันเยี่ยมมากที่ในที่สุดฉันก็สามารถใช้โค้ดสำหรับสิ่งที่ตั้งใจจะใช้ :) แต่ทำไมฉันถึงต้องการสิ่งอื่นนอกเหนือจากภาษาโปรแกรมเพื่อทำสิ่งนั้น?
Pavel Feldman

ฉันคิดว่าเป็นเพราะ XML อนุญาตให้มีการเปลี่ยนแปลงรันไทม์หรืออย่างน้อยก็เปลี่ยนการกำหนดค่าโดยไม่ต้องคอมไพล์โครงการใหม่
Romain Verdier

1

ง่ายต่อการรวมการกำหนดค่าบางส่วนเข้ากับการกำหนดค่าขั้นสุดท้ายที่สมบูรณ์

ตัวอย่างเช่นในเว็บแอปพลิเคชันโดยทั่วไปโมเดลมุมมองและคอนโทรลเลอร์จะระบุไว้ในไฟล์คอนฟิกูเรชันแยกต่างหาก ใช้วิธีการประกาศคุณสามารถโหลดตัวอย่างเช่น:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

หรือโหลดด้วย UI ที่แตกต่างกันและตัวควบคุมพิเศษบางตัว:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

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


1

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

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


นั่นเป็นจุดที่ถูกต้อง แต่การกำหนดค่าสปริงมักจะค่อนข้างซับซ้อน แม้ว่าจะง่ายต่อการเปลี่ยนอายุ แต่ผู้ดูแลระบบยังคงต้องจัดการกับไฟล์ xml ขนาดใหญ่ที่เขาไม่จำเป็นต้องเข้าใจทั้งหมด ไม่ดีกว่าที่จะแยกส่วนที่ควรจะกำหนดค่าเป็นสิ่งที่ง่ายกว่าการกำหนดค่า XML ฤดูใบไม้ผลิหรือไม่? เช่นเดียวกับไฟล์คุณสมบัติที่มีบรรทัดเดียว "age = 23" และไม่อนุญาตให้ผู้ดูแลระบบเปลี่ยนแปลงรายละเอียดอื่น ๆ เช่นชื่อคลาส ฯลฯ ที่ต้องใช้ความรู้เกี่ยวกับโครงสร้างโปรแกรมภายใน
Pavel Feldman

ฉันเพิ่งทำงานในโปรเจ็กต์ที่มีโค้ด Java และ XSLT ผสมกัน ทีมเป็นส่วนผสมของคนที่แข็งแกร่งใน Java (และอาจไม่ค่อยสะดวกในการทำงานกับ XML และ XSLT) และคนที่ทำงานกับ XML และ XSLT ได้ดีมาก (และไม่ค่อยพอใจกับ Java) เนื่องจากการกำหนดค่าจะได้รับการจัดการโดยกลุ่มที่สองจึงเหมาะสมที่จะใช้ Spring และมีการกำหนดค่า XML กล่าวอีกนัยหนึ่ง Spring แก้ปัญหาการแบ่งงานกันทำในทีม มันไม่ได้แก้ปัญหา "ทางเทคนิค"; ในแง่ที่การกำหนดค่าสามารถทำได้อย่างง่ายดายด้วยโค้ด Java
Dawood ibn Kareem

'บุคลากรสายสนับสนุน' จะรู้อะไรเกี่ยวกับการต้องเปลี่ยนคลาสบางอย่างที่สร้างขึ้นภายในตู้คอนเทนเนอร์แบบพึ่งพา? ภายใต้สมมติฐานว่าเป็นงานของนักพัฒนาที่จะทำสิ่งนี้จริงหรือ?
Jimbo

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

1

จากฤดูใบไม้ผลิฉันสามารถให้คำตอบคุณได้สองข้อ

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

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

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


0

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

หากไม่มีเหตุผลว่าทำไมคุณสมบัติจึงเปลี่ยนไปก็ไม่มีเหตุผลที่จะกำหนดค่าด้วยวิธีนี้


0

กรณีของคุณง่ายมากดังนั้นจึงไม่จำเป็นต้องมีคอนเทนเนอร์ IoC (Inversion of Control) เช่น Spring ในทางกลับกันเมื่อคุณ "ตั้งโปรแกรมอินเทอร์เฟซไม่ใช่การใช้งาน" (ซึ่งเป็นแนวทางปฏิบัติที่ดีใน OOP) คุณสามารถมีโค้ดดังนี้:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

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

  • การกำหนดค่าภายนอกของการทำแผนที่ระหว่างอินเทอร์เฟซและการใช้งานคอนกรีต
  • คอนเทนเนอร์ IoC จัดการกับปัญหาที่ยุ่งยากบางอย่างเช่นการแก้ไขกราฟการอ้างอิงที่ซับซ้อนการจัดการอายุการใช้งานของส่วนประกอบเป็นต้น
  • คุณประหยัดเวลาในการเข้ารหัสเนื่องจากคุณระบุการแมปอย่างเปิดเผยไม่ใช่ในรหัสขั้นตอน
  • หลักการ Inversion of Control ช่วยให้สามารถทดสอบหน่วยได้ง่ายเพราะคุณสามารถแทนที่การใช้งานจริงด้วยของปลอมได้ (เช่นการแทนที่ฐานข้อมูล SQL ด้วยในหน่วยความจำ)

0

การเริ่มต้นในไฟล์กำหนดค่า XML จะทำให้การดีบัก / การปรับใช้งานง่ายขึ้นกับไคลเอนต์ที่ติดตั้งแอปของคุณบนคอมพิวเตอร์ (เพราะไม่ต้องการการคอมไพล์ใหม่ + การเปลี่ยนไฟล์ไบนารี)


-2

หนึ่งในเหตุผลที่น่าสนใจที่สุดคือ " หลักการของฮอลลีวูด " อย่าโทรหาเราเราจะโทรหาคุณ ส่วนประกอบไม่จำเป็นต้องทำการค้นหาส่วนประกอบและบริการอื่น ๆ เอง แต่จะมีให้โดยอัตโนมัติ ใน Java หมายความว่าไม่จำเป็นต้องทำการค้นหา JNDI ภายในคอมโพเนนต์อีกต่อไป

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


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

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