ลองมาตัวอย่างง่าย ๆ - บางทีคุณกำลังฉีดวิธีการเข้าสู่ระบบ
ฉีดชั้นเรียน
class Worker: IWorker
{
ILogger _logger;
Worker(ILogger logger)
{
_logger = logger;
}
void SomeMethod()
{
_logger.Debug("This is a debug log statement.");
}
}
ฉันคิดว่ามันค่อนข้างชัดเจนว่าเกิดอะไรขึ้น ยิ่งไปกว่านั้นถ้าคุณใช้คอนเทนเนอร์ IoC คุณไม่จำเป็นต้องใส่อะไรลงไปอย่างชัดเจนคุณเพียงแค่เพิ่มไปที่รูทองค์ประกอบของคุณ:
container.RegisterType<ILogger, ConcreteLogger>();
container.RegisterType<IWorker, Worker>();
....
var worker = container.Resolve<IWorker>();
เมื่อทำการดีบั๊กWorker
ผู้พัฒนาเพียงต้องการศึกษารูทขององค์ประกอบเพื่อกำหนดว่าจะใช้คลาสคอนกรีตได้อย่างไร
หากผู้พัฒนาต้องการตรรกะที่ซับซ้อนกว่านี้เขามีอินเทอร์เฟซทั้งหมดให้ทำงานกับ:
void SomeMethod()
{
if (_logger.IsDebugEnabled) {
_logger.Debug("This is a debug log statement.");
}
}
ฉีดวิธีการ
class Worker
{
Action<string> _methodThatLogs;
Worker(Action<string> methodThatLogs)
{
_methodThatLogs = methodThatLogs;
}
void SomeMethod()
{
_methodThatLogs("This is a logging statement");
}
}
methodThatLogs
ครั้งแรกที่แจ้งให้ทราบว่าพารามิเตอร์คอนสตรัคมีชื่ออีกต่อไปตอนนี้ สิ่งนี้จำเป็นเพราะคุณไม่สามารถบอกได้ว่าAction<string>
ควรทำอะไร ด้วยอินเทอร์เฟซมันชัดเจนอย่างสมบูรณ์ แต่ที่นี่เราต้องหันไปพึ่งการตั้งชื่อพารามิเตอร์ สิ่งนี้ดูเหมือนว่าเชื่อถือได้น้อยกว่าและยากที่จะบังคับใช้ในระหว่างการสร้าง
ตอนนี้เราจะฉีดวิธีนี้ได้อย่างไร คอนเทนเนอร์ IoC จะไม่ทำเพื่อคุณ Worker
ดังนั้นคุณจะเหลือฉีดอย่างชัดเจนเมื่อคุณยกตัวอย่าง นี่ทำให้เกิดปัญหาสองสามข้อ:
- มันเป็นงานมากกว่าที่จะยกตัวอย่าง
Worker
- นักพัฒนาที่พยายามแก้ไขข้อบกพร่อง
Worker
จะพบว่าเป็นการยากที่จะทราบว่ามีการเรียกใช้อินสแตนซ์ที่เป็นรูปธรรมอย่างไร พวกเขาไม่สามารถปรึกษารูทองค์ประกอบได้ พวกเขาจะต้องติดตามรหัส
ถ้าเราต้องการตรรกะที่ซับซ้อนกว่านี้ล่ะ? เทคนิคของคุณเปิดเผยเพียงหนึ่งวิธี ตอนนี้ฉันคิดว่าคุณสามารถอบข้าวของที่ซับซ้อนลงในแลมบ์ดาได้:
var worker = new Worker((s) => { if (log.IsDebugEnabled) log.Debug(s) } );
แต่เมื่อคุณเขียนบททดสอบคุณจะทดสอบแลมบ์ดาอย่างไร? ไม่ระบุชื่อดังนั้นกรอบการทดสอบหน่วยของคุณไม่สามารถยกตัวอย่างได้โดยตรง บางทีคุณสามารถหาวิธีที่ชาญฉลาดในการทำ แต่อาจเป็น PITA ที่ใหญ่กว่าการใช้อินเทอร์เฟซ
สรุปความแตกต่าง:
- การฉีดเพียงวิธีเดียวทำให้ยากที่จะอนุมานจุดประสงค์ในขณะที่ส่วนต่อประสานนั้นสื่อสารวัตถุประสงค์อย่างชัดเจน
- การฉีดเพียงวิธีเดียวจะทำให้ฟังก์ชั่นการใช้งานน้อยลงสำหรับคนในชั้นเรียน แม้ว่าคุณไม่ต้องการมันวันนี้คุณอาจต้องการมันในวันพรุ่งนี้
- คุณไม่สามารถฉีดวิธีการเดียวโดยอัตโนมัติโดยใช้คอนเทนเนอร์ IoC
- คุณไม่สามารถบอกได้จากรูทองค์ประกอบที่คลาสคอนกรีตทำงานในบางกรณี
- มันเป็นปัญหาที่หน่วยทดสอบการแสดงออกแลมบ์ดาตัวเอง
หากคุณตกลงกับข้างต้นทั้งหมดแล้วก็ตกลงที่จะฉีดเพียงวิธี มิฉะนั้นฉันจะแนะนำให้คุณติดกับประเพณีและฉีดอินเทอร์เฟซ