อะไรคือความแตกต่างระหว่างการใช้การฉีดพึ่งพากับคอนเทนเนอร์และการใช้ตัวระบุบริการ


107

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

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

ความแตกต่างระหว่างสองคืออะไร ทำไมฉันถึงเลือกอันหนึ่งมากกว่าอีกอัน?


3
สิ่งนี้ถูกถาม (และตอบ) บน StackOverflow: stackoverflow.com/questions/8900710/…
Kyralessa

2
ในความคิดของฉันมันไม่ใช่เรื่องแปลกเลยสำหรับนักพัฒนาที่จะหลอกลวงผู้อื่นให้คิดว่าผู้ให้บริการของพวกเขาคือการพึ่งพาการฉีด พวกเขาทำเช่นนั้นเพราะการฉีดพึ่งพามักจะคิดว่าจะสูงขึ้น
Gherman


1
ฉันประหลาดใจที่ไม่มีใครพูดถึงด้วย Service Locators มันยากที่จะรู้ว่าเมื่อใดที่ทรัพยากรชั่วคราวสามารถถูกทำลายได้ ฉันคิดเสมอว่านั่นเป็นเหตุผลหลัก
Buh Buh

คำตอบ:


126

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

คอนเทนเนอร์ที่ให้การอ้างอิงผ่านอาร์กิวเมนต์ตัวสร้างให้ความคมชัดมากที่สุด เราเห็นขวาขึ้นด้านหน้าที่วัตถุที่ต้องการทั้งและAccountRepository PasswordStrengthEvaluatorเมื่อใช้บริการระบุตำแหน่งข้อมูลนั้นจะปรากฏน้อยลงในทันที คุณจะเห็นกรณีทันทีที่วัตถุมีโอ้การพึ่งพา 17 รายการและพูดกับตัวเองว่า "อืมมันดูเหมือนจะเยอะมากแล้วเกิดอะไรขึ้นในนั้น" การโทรไปยังที่ตั้งผู้ให้บริการสามารถแพร่กระจายไปทั่ววิธีการต่าง ๆ และซ่อนอยู่ภายใต้ตรรกะที่มีเงื่อนไขและคุณอาจไม่ทราบว่าคุณได้สร้าง "คลาสพระเจ้า" ซึ่งเป็นสิ่งที่ทำทุกอย่าง บางทีคลาสนั้นอาจถูกปรับโครงสร้างใหม่เป็น 3 คลาสที่เล็กกว่าซึ่งมีสมาธิมากกว่าและทดสอบได้มากกว่า

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

ค้นหา "Serivce Locator เป็น Anti-Pattern" สำหรับบทความของ Mark Seeman เกี่ยวกับเรื่องนี้ หากคุณอยู่ในโลก. Net รับหนังสือของเขา มันดีมาก


1
อ่านคำถามที่ฉันคิดเกี่ยวกับAdaptive Code ผ่าน C #โดย Gary McLean Hall ซึ่งสอดคล้องกับคำตอบนี้ค่อนข้างดี มันมีการเปรียบเทียบที่ดีเช่นตัวระบุตำแหน่งบริการเป็นกุญแจสู่ความปลอดภัย เมื่อส่งไปยังชั้นเรียนมันอาจสร้างการพึ่งพาที่จะไม่ง่ายที่จะมองเห็น
เดนนิส

10
สิ่งหนึ่งที่ IMO จะต้องมีการเพิ่มให้กับconstructor supplied dependenciesVS service locatorคือหนึ่งในอดีตสามารถ verfied รวบรวมเวลาในขณะที่หลังหนึ่งสามารถเพียง แต่ได้รับการยืนยันรันไทม์
andras

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

1
เกี่ยวกับการทดสอบ - But that's more work than specifying dependencies in the object's constructor.ฉันต้องการคัดค้าน ด้วยตัวระบุตำแหน่งบริการคุณจะต้องระบุการขึ้นต่อกัน 3 อย่างที่คุณต้องการสำหรับการทดสอบของคุณ ด้วย DI-Constructor คุณจะต้องระบุ ALL 10 ทั้งหมดแม้ว่าจะไม่ได้ใช้ 7 ก็ตาม
Vilx-

4
@ Vilx- หากคุณมีพารามิเตอร์คอนสตรัคเตอร์ที่ไม่ได้ใช้หลายครั้งก็เป็นไปได้ที่คลาสของคุณจะละเมิดหลักการความรับผิดชอบเดี่ยว
RB

79

ลองนึกภาพคุณเป็นคนงานในโรงงานที่ทำให้เป็นรองเท้า

คุณต้องรับผิดชอบในการประกอบรองเท้าและดังนั้นคุณต้องมีหลายอย่างในการทำเช่นนั้น

  • หนังสัตว์
  • เทปวัด
  • กาว
  • เล็บ
  • ค้อน
  • กรรไกร
  • เชือกผูกรองเท้า

และอื่น ๆ

คุณกำลังทำงานในโรงงานและพร้อมที่จะเริ่ม คุณมีรายการคำแนะนำเกี่ยวกับวิธีดำเนินการ แต่คุณยังไม่มีวัสดุหรือเครื่องมือใด ๆ

ผู้ให้บริการเป็นเหมือนหัวหน้าคนงานที่สามารถช่วยให้คุณได้รับสิ่งที่คุณต้องการ

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

คุณควรหวังว่าคุณจะไม่ขอสิ่งที่คาดไม่ถึง หาก Locator ไม่ได้รับการแจ้งล่วงหน้าเกี่ยวกับเครื่องมือหรือวัสดุเฉพาะพวกเขาจะไม่สามารถหามาให้คุณได้และพวกเขาจะยักใส่คุณ

ที่ตั้งบริการ

พึ่งพาการฉีด (DI) ตู้คอนเทนเนอร์เป็นเหมือนกล่องใหญ่ที่ได้รับเต็มไปด้วยทุกสิ่งที่ทุกคนต้องการที่จุดเริ่มต้นของวัน

ขณะที่โรงงานจะเริ่มต้นขึ้นที่บิ๊กบอสที่รู้จักในฐานะรากองค์ประกอบคว้าภาชนะและมือทุกอย่างกับผู้จัดการสายงาน

ผู้จัดการสายงานมีสิ่งที่พวกเขาต้องการในการปฏิบัติหน้าที่ของพวกเขาสำหรับวันนี้ พวกเขาใช้สิ่งที่พวกเขามีและผ่านสิ่งที่ต้องการให้ผู้ใต้บังคับบัญชา

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

หัวหน้าคนงานของคุณกระจายสิ่งที่คุณต้องการให้คุณและคนงานคนอื่น ๆ โดยที่คุณไม่ต้องถามพวกเขาเลย

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

ภาชนะฉีดพึ่งพา


45
นี่คือคำอธิบายที่ยอดเยี่ยมเกี่ยวกับสิ่งที่ทั้งสองสิ่งนั้นไดอะแกรมดูดีมากเช่นกัน! แต่นี่ไม่ได้ตอบคำถามของ "ทำไมต้องเลือกอย่างใดอย่างหนึ่งมากกว่าที่อื่น"?
Matthieu M.

21
"คุณควรหวังว่าคุณจะไม่ขอสิ่งที่คาดไม่ถึงแม้ว่าหาก Locator ไม่ได้รับการแจ้งล่วงหน้าเกี่ยวกับเครื่องมือหรือวัสดุที่เฉพาะเจาะจง" แต่นั่นก็อาจเป็นจริงได้เช่นกันกับคอนเทนเนอร์ DI
Kenneth K.

5
@ Frankankopkins หากคุณไม่ได้ลงทะเบียนอินเตอร์เฟส / คลาสด้วย DI container ของคุณรหัสของคุณจะยังคงรวบรวมและมันจะล้มเหลวทันทีที่รันไทม์
Kenneth K.

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

3
คำตอบที่ดี แต่ฉันคิดว่ามันคิดถึงสิ่งอื่น นั่นคือถ้าคุณถามหัวหน้าคนงานในขั้นตอนใด ๆ สำหรับช้างและเขาไม่ทราบวิธีการที่จะได้รับหนึ่งเขาจะได้รับหนึ่งสำหรับคุณไม่มีคำถาม asked- แม้ว่าคุณไม่จำเป็นต้องใช้ และมีคนพยายามที่จะแก้ไขปัญหาบนพื้น (นักพัฒนาถ้าคุณจะ) จะสงสัยว่า wtf เป็นช้างทำที่นี่บนโต๊ะนี้จึงทำให้ยากสำหรับพวกเขาที่จะให้เหตุผลเกี่ยวกับสิ่งที่ผิดพลาดจริง ในขณะที่คุณเป็นคนงานชนชั้นประกาศล่วงหน้าทุกการพึ่งพาที่คุณต้องการก่อนที่คุณจะเริ่มงานทำให้ง่ายขึ้นที่จะให้เหตุผลเกี่ยวกับ
Stephen Byrne

10

สองคะแนนพิเศษที่ฉันพบเมื่อใยเว็บ:

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

4

ฉันมางานปาร์ตี้สายนี้ แต่ฉันไม่สามารถต้านทานได้

อะไรคือความแตกต่างระหว่างการใช้การฉีดพึ่งพากับคอนเทนเนอร์และการใช้ตัวระบุบริการ

บางครั้งก็ไม่มีเลย สิ่งที่ทำให้แตกต่างคือสิ่งที่รู้เกี่ยวกับอะไร

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

นี่หมายความว่าถ้าคุณต้องการหลีกเลี่ยงตัวระบุตำแหน่งบริการคุณไม่สามารถใช้คอนเทนเนอร์ได้หรือไม่? ไม่คุณเพียงแค่ต้องป้องกันไม่ให้ลูกค้ารู้เกี่ยวกับคอนเทนเนอร์ ความแตกต่างหลักคือที่ที่คุณใช้คอนเทนเนอร์

ช่วยบอกความต้องการClient ภาชนะที่มีDependencyDependency

class Client { 
    Client() { 
        BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
        this.dependency = (Dependency) beanfactory.getBean("dependency");        
    }
    Dependency dependency;
}

เราได้ปฏิบัติตามเพียงแค่รูปแบบการบริการระบุตำแหน่งเพราะรู้วิธีที่จะหาClient Dependencyแน่ใจว่าจะใช้รหัสยากClassPathXmlApplicationContextแต่แม้ว่าคุณจะฉีดที่คุณยังมีบริการค้นหาเพราะสายClientbeanfactory.getBean()

เพื่อหลีกเลี่ยงตำแหน่งของบริการคุณไม่จำเป็นต้องทิ้งคอนเทนเนอร์นี้ คุณแค่ย้ายมันออกไปClientดังนั้นClientไม่รู้เรื่องเลย

class EntryPoint { 
    public static void main(String[] args) {
        BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
        Client client = (Client) beanfactory.getBean("client");

        client.start();
    }
}

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="dependency" class="Dependency">
    </bean>

    <bean id="client" class="Client">
        <constructor-arg value="dependency" />        
    </bean>
</beans>

สังเกตว่าClientตอนนี้ไม่มีความคิดว่ามีคอนเทนเนอร์อยู่:

class Client { 
    Client(Dependency dependency) { 

        this.dependency = dependency;        
    }
    Dependency dependency;
}

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

ที่ย้ายโครงสร้างแบบคงที่ทั้งหมดไปยังคอนเทนเนอร์ XML แต่ยังทำให้ลูกค้าของคุณไม่รู้วิธีการค้นหาการพึ่งพาของพวกเขาอย่างมีความสุข

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


1

ฉันคิดว่าวิธีที่ง่ายที่สุดในการทำความเข้าใจความแตกต่างระหว่างทั้งสองและทำไม DI container จึงดีกว่า Service locator มากคือการคิดว่าทำไมเราถึงต้องพึ่งการผกผันในตอนแรก

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

ลองดูที่คลาสต่อไปนี้:

public class MySpecialStringWriter
{
  private readonly IOutputProvider outputProvider;
  public MySpecialFormatter(IOutputProvider outputProvider)
  {
    this.outputProvider = outputProvider;
  }

  public void OutputString(string source)
  {
    this.outputProvider.Output("This is the string that was passed: " + source);
  }
}

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

ดูที่คลาสเดียวกันด้วยตัวระบุบริการ:

public class MySpecialStringWriter
{
  private readonly ServiceLocator serviceLocator;
  public MySpecialFormatter(ServiceLocator serviceLocator)
  {
    this.serviceLocator = serviceLocator;
  }

  public void OutputString(string source)
  {
    this.serviceLocator.OutputProvider.Output("This is the string that was passed: " + source);
  }
}

ตอนนี้ฉันได้เพิ่มตัวระบุบริการเป็นการอ้างอิง นี่คือปัญหาที่ชัดเจนทันที:

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

ดังนั้นทำไมเราไม่ทำให้ตัวระบุตำแหน่งเซอร์วิสเป็นคลาสแบบสแตติก ลองดู:

public class MySpecialStringWriter
{
  public void OutputString(string source)
  {
    ServiceLocator.OutputProvider.Output("This is the string that was passed: " + source);
  }
}

มันง่ายกว่านี้ใช่มั้ย

ไม่ถูกต้อง.

สมมติว่า IOutputProvider ดำเนินการโดยเว็บเซอร์วิสที่ใช้เวลานานซึ่งเขียนสตริงในฐานข้อมูลต่าง ๆ สิบห้าฐานข้อมูลทั่วโลกและใช้เวลานานมากในการทำให้เสร็จสมบูรณ์

ลองทดสอบคลาสนี้กัน เราต้องการการใช้งาน IOutputProvider ที่แตกต่างกันสำหรับการทดสอบ เราจะเขียนแบบทดสอบได้อย่างไร

เราจำเป็นต้องทำการกำหนดค่าแฟนซีบางอย่างในคลาส ServiceLocator เพื่อใช้งาน IOutputProvider ที่แตกต่างกันเมื่อมันถูกเรียกโดยการทดสอบ แม้แต่การเขียนประโยคนั้นก็เจ็บปวด การดำเนินการมันจะทรมานและมันจะเป็นฝันร้ายของการบำรุงรักษา เราไม่จำเป็นต้องแก้ไขคลาสเฉพาะสำหรับการทดสอบโดยเฉพาะถ้าคลาสนั้นไม่ใช่คลาสที่เราพยายามทำการทดสอบ

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

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

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


Service Locators (SL) และ Dependency Injection (DI) ทั้งคู่แก้ปัญหาเดียวกันในลักษณะที่คล้ายคลึงกัน ข้อแตกต่างถ้าหากคุณ "บอก" DI หรือ "ขอ" SL สำหรับการอ้างอิง
Matthew Whited

@MatthewWhited ความแตกต่างที่สำคัญคือจำนวนการอ้างอิงโดยนัยที่คุณใช้กับตัวระบุตำแหน่งบริการ และนั่นทำให้ความแตกต่างอย่างมากต่อการบำรุงรักษาในระยะยาวและเสถียรภาพของรหัส
สตีเฟ่น

มันไม่จริง คุณมีจำนวนการพึ่งพาเหมือนกันทั้งสองทาง
Matthew Whited

เริ่มแรกใช่ แต่คุณสามารถพึ่งพาได้ด้วยตัวระบุตำแหน่งบริการโดยไม่ทราบว่าคุณกำลังพึ่งพา ซึ่งเอาชนะส่วนใหญ่ของเหตุผลที่ว่าทำไมเราต้องพึ่งพาการผกผันในตอนแรก ชั้นหนึ่งขึ้นอยู่กับคุณสมบัติ A และ B อีกชั้นหนึ่งขึ้นอยู่กับ B และ C ทันใดนั้นผู้ให้บริการจะกลายเป็นชนชั้นพระเจ้า คอนเทนเนอร์ DI ไม่ได้และคลาสสองคลาสนั้นขึ้นอยู่กับ A และ B และ B และ C ตามลำดับเท่านั้น ทำให้การรีแฟคเตอร์ทำได้ง่ายขึ้นร้อยเท่า ตัวระบุตำแหน่งบริการนั้นร้ายกาจในสิ่งที่พวกเขาปรากฏเช่นเดียวกับ DI แต่พวกเขาไม่ได้
Stephen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.