เมื่อเร็ว ๆ นี้ฉันได้อ่านบทความของ Mark Seemannเกี่ยวกับรูปแบบการต่อต้าน Service Locator
ผู้เขียนชี้ให้เห็นเหตุผลหลักสองประการที่ว่าทำไม ServiceLocator จึงต่อต้านรูปแบบ:
ปัญหาการใช้งาน API (ซึ่งฉันก็สบายดี)
เมื่อคลาสใช้ตัวระบุตำแหน่งบริการมันยากมากที่จะเห็นการอ้างอิงเนื่องจากในกรณีส่วนใหญ่คลาสจะมีตัวสร้าง PARAMETERLESS เพียงตัวเดียว ในทางตรงกันข้ามกับ ServiceLocator วิธี DI เปิดเผยการอ้างอิงอย่างชัดเจนผ่านพารามิเตอร์ของตัวสร้างเพื่อให้เห็นการอ้างอิงได้ง่ายใน IntelliSenseปัญหาการบำรุงรักษา (ซึ่งทำให้ฉันงง)
พิจารณาตัวอย่างต่อไปนี้
เรามีคลาส'MyType'ซึ่งใช้วิธีการระบุตำแหน่งบริการ:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
ตอนนี้เราต้องการเพิ่มการอ้างอิงอื่นให้กับคลาส 'MyType'
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
และนี่คือจุดเริ่มต้นของความเข้าใจผิดของฉัน ผู้เขียนกล่าวว่า:
มันยากกว่ามากที่จะบอกได้ว่าคุณกำลังแนะนำการเปลี่ยนแปลงที่ทำลายล้างหรือไม่ คุณต้องเข้าใจแอปพลิเคชันทั้งหมดที่ใช้ Service Locator และคอมไพเลอร์จะไม่ช่วยคุณ
แต่รอสักครู่ถ้าเราใช้วิธี DI เราจะแนะนำการพึ่งพากับพารามิเตอร์อื่นในตัวสร้าง (ในกรณีของการฉีดตัวสร้าง) และปัญหาจะยังคงมี หากเราอาจลืมตั้งค่า ServiceLocator เราอาจลืมเพิ่มการแมปใหม่ในคอนเทนเนอร์ IoC ของเราและวิธีการ DI อาจมีปัญหารันไทม์เหมือนกัน
นอกจากนี้ผู้เขียนยังกล่าวถึงปัญหาในการทดสอบหน่วย แต่เราจะไม่มีปัญหากับแนวทาง DI หรือไม่? เราไม่จำเป็นต้องอัปเดตการทดสอบทั้งหมดซึ่งเป็นอินสแตนซ์ของคลาสนั้นหรือไม่ เราจะอัปเดตให้พวกเขาผ่านการอ้างอิงแบบจำลองใหม่เพื่อให้การทดสอบของเรารวบรวมได้ และฉันไม่เห็นประโยชน์ใด ๆ จากการอัปเดตและการใช้เวลา
ฉันไม่ได้พยายามปกป้องวิธีการระบุตำแหน่งบริการ แต่ความเข้าใจผิดนี้ทำให้ฉันคิดว่ากำลังสูญเสียสิ่งที่สำคัญมากไป ใครช่วยขจัดความสงสัยของฉันได้ไหม
อัปเดต (สรุป):
คำตอบสำหรับคำถามของฉัน "Is Service Locator an anti-pattern" ขึ้นอยู่กับสถานการณ์จริงๆ และแน่นอนฉันไม่แนะนำให้ตัดมันออกจากรายการเครื่องมือของคุณ อาจมีประโยชน์มากเมื่อคุณเริ่มจัดการกับรหัสเดิม หากคุณโชคดีพอที่จะอยู่ในจุดเริ่มต้นของโครงการแนวทาง DI อาจเป็นทางเลือกที่ดีกว่าเนื่องจากมีข้อได้เปรียบเหนือ Service Locator
และนี่คือความแตกต่างหลักที่ทำให้ฉันไม่ใช้ Service Locator สำหรับโครงการใหม่ของฉัน:
- ชัดเจนและสำคัญที่สุด: Service Locator ซ่อนการอ้างอิงคลาส
- หากคุณใช้คอนเทนเนอร์ IoC บางตัวอาจจะสแกนตัวสร้างทั้งหมดเมื่อเริ่มต้นเพื่อตรวจสอบการอ้างอิงทั้งหมดและให้ข้อเสนอแนะทันทีเกี่ยวกับการแมปที่ขาดหายไป (หรือการกำหนดค่าที่ไม่ถูกต้อง) เป็นไปไม่ได้หากคุณใช้คอนเทนเนอร์ IoC ของคุณเป็นตัวระบุตำแหน่งบริการ
สำหรับรายละเอียดอ่านคำตอบที่ยอดเยี่ยมซึ่งได้รับด้านล่าง