เกมค้าปลีกใช้ "การควบคุมแบบผกผัน" และ "การฉีดพึ่งพา" หรือไม่?


30

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


ฉันคิดว่าในโลกนั้นมีความสำคัญเหนือสิ่งอื่นใดเนื่องจากผู้ใช้จำนวนมากจะได้รับผลกระทบต่ำกว่าโปรแกรมเมอร์โดยใช้รหัสไม่ดี
Bart van Heukelom

การฉีดที่ขึ้นต่อกันดูเหมือนจะเป็นระบบที่ใช้ส่วนประกอบ แต่คุณจะมีตัวอย่างของวิธีการที่จะควบคุมการผกผันได้หรือไม่?
ADB

เนื่องจากส่วนใหญ่ของเธรดนี้ดูเหมือนจะเข้าใจผิดเกี่ยวกับสิ่งที่ IoC คือและสิ่งที่แก้ไขและ OP ไม่ได้ถามจริง ๆ ว่าในสถานที่แรกที่ฉันจะชี้ไปที่นี่สำหรับผู้เข้าชมในอนาคต: sebaslab.com/ioc-container-unity-part-1
Boris Callens

ใช่. ในความเป็นจริงที่หายากมีการพูดคุยเกี่ยวกับวิธีที่พวกเขามีการดำเนินการทดสอบของพวกเขาในทะเลโจร - youtube.com/watch?v=KmaGxprTUfI&t=1s น่าเสียดายที่พวกเขาไม่ได้พูดมากเกินไปเกี่ยวกับ Inversion of Control ใน Unreal Engine แต่ฉันได้เขียนโครงการที่แสดงให้เห็นว่ามันทำงานอย่างไร: github.com/jimmyt1988/UE- การทดสอบ
Jimmyt1988

คำตอบ:


45

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

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

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


5
+1 - ฉันยอมรับว่าชุมชน Java ดูเหมือนจะมีความซับซ้อนเกินกว่าสิ่งที่ดูเหมือนจะเป็นความคิดที่ง่ายมาก
Chris Howe

4
แนวคิดไม่จำเป็นว่าคุณจะต้องสลับการใช้งานที่แตกต่างกันในการผลิต แต่คุณอาจต้องการฉีดการนำไปใช้งานพิเศษเพื่ออำนวยความสะดวกในการทดสอบอัตโนมัติ ในเรื่องนั้น DI / IoC อาจมีประโยชน์ในเกมอย่างแน่นอน แต่คุณต้องการให้ขอบเขตที่เหมาะสม คุณไม่จำเป็นต้องใช้ความละเอียดการบริการครั้งเดียวมากกว่าสองสามครั้งในระดับสูง - คุณไม่ต้องการแก้ไขบริการสำหรับวัตถุเล็ก ๆ ทุกตัวในเกมและไม่ใช่ทุกเฟรมหรืออะไรอย่างนั้น
Mike Strobel

2
@Thomas Dufour: แนวคิดของการทดสอบไม่สามารถพิสูจน์อะไรได้เลย มันเป็นเพียงจุดข้อมูล คุณสามารถมีการทดสอบผ่าน 100,000 ครั้งโดยไม่ต้องพิสูจน์ว่ามันจะผ่านการรัน 1,001,001 พิสูจน์ได้มาจากการวิเคราะห์เชิงตรรกะของเรื่อง ฉันจะยืนยันว่าคอนเทนเนอร์ IoC เหล่านี้และสิ่งที่คล้ายกันทำให้การทดสอบง่ายขึ้นโดยใช้ค่าใช้จ่ายในการพิสูจน์ความถูกต้องที่หนักกว่าและฉันเชื่อว่านั่นเป็นสิ่งที่ไม่ดี
Kylotan

13
@Kylotan แนวคิดของการทดสอบไม่เคยพยายามที่จะพิสูจน์อะไร มันพยายามที่จะแสดงให้เห็นว่าพฤติกรรมกับอินพุตที่กำหนดนั้นเป็นไปตามที่คาดไว้ ยิ่งแสดงพฤติกรรมที่ถูกต้องมากเท่าไหร่ความเชื่อมั่นของคุณก็ยิ่งมากขึ้นว่าฟังก์ชั่นโดยรวมนั้นถูกต้อง แต่ก็ไม่เคย 100% คำสั่งที่น้อยที่สุดอินเตอร์เฟซพิสูจน์สิ่งที่น่าหัวเราะ
dash-tom-bang

5
@Alex Schearer: ฉันเกรงว่าฉันไม่สามารถยอมรับได้ว่าต้องใช้ระบบคอนเทนเนอร์ IoC อย่างเป็นทางการและมักจะสร้างข้อโต้แย้งคอนสตรัคเตอร์เพิ่มเติมหรือคลาสโรงงานเพื่ออำนวยความสะดวกในการทดสอบไม่ว่าจะด้วยวิธีใดก็ตาม ทำให้มันคลายคู่ ในความเป็นจริงมันค่อนข้างเหยียบย่ำในการห่อหุ้มซึ่งเป็นกุญแจสำคัญของ OOP แทนที่จะพึ่งพา TDD เพื่อผลักดันการออกแบบและหวังว่าผลลัพธ์ที่ดีจะปรากฏขึ้นผู้คนสามารถปฏิบัติตามหลักการของ SOLID ได้ตั้งแต่แรก
Kylotan

17

รูปแบบกลยุทธ์ , องค์ประกอบ , การพึ่งพาการฉีดล้วนมีความสัมพันธ์กันอย่างใกล้ชิด

เนื่องจากรูปแบบกลยุทธ์เป็นรูปแบบของการฉีดขึ้นอยู่กับว่าถ้าคุณดูที่เครื่องยนต์เช่น Unity เช่นพวกเขาจะยึดตามหลักการนี้อย่างสมบูรณ์ การใช้ส่วนประกอบ (รูปแบบกลยุทธ์) ของพวกเขาฝังลึกลงในเครื่องมือทั้งหมดของพวกเขา

ประโยชน์หลักอย่างหนึ่งนอกเหนือจากการนำส่วนประกอบมาใช้ซ้ำคือการหลีกเลี่ยงลำดับชั้นระดับลึกที่หวั่นกลัว

นี่คือบทความของมิคเวสต์ที่พูดถึงวิธีที่เขาแนะนำระบบประเภทนี้ในซีรีย์เกมของTony Hawkโดย Neversoft

วิวัฒนาการลำดับขั้นของคุณ

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


2
+1, วิวัฒนาการลำดับชั้นของคุณเป็นลิงค์ที่ยอดเยี่ยมที่ฉันลืมไปโดยสิ้นเชิง สไลด์ Scott Bilas ก็ดีเช่นกัน - ลิงก์ที่ถูกต้องสำหรับสิ่งเหล่านี้คือ ( scottbilas.com/files/2002/gdc_san_jose/game_objects_slides.pdf ) มีอีกหนึ่งชุดของสไลด์ที่เกี่ยวข้อง แต่ฉันลืมไปแล้วว่า ...
leander

บทความใน Games Gems 5 (ฉันคิดว่า) โดย Bjarne Rene
Chris Howe

13

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

class Game {
    void Load() {
        this.Sprite.Load(); // loads resource for drawing later
    }
}

class Sprite {
    void Load() {
        FileReader reader = new FileReader("path/to/resource.gif");
        // load image from file
    }
}

ในข้างต้นเป็นที่ชัดเจนว่ามีการพึ่งพาได้Sprite.Load FileReaderเมื่อคุณต้องการทดสอบวิธีที่คุณต้องการดังต่อไปนี้:

  1. ระบบไฟล์ในสถานที่
  2. ไฟล์ทดสอบที่จะโหลดจากระบบไฟล์
  3. ความสามารถในการทริกเกอร์ข้อผิดพลาดของระบบไฟล์ทั่วไป

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

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

หากเราต้องเขียนSprite.Loadวิธีข้างต้นอีกครั้งเราอาจจะจบลงด้วย:

class Sprite {
    void Load(IReader reader) {
        // load image through reader
    }
}

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

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

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


2
อเล็กซ์: ไม่มีใครคัดค้านการส่งผ่านวัตถุที่สร้างขึ้นแล้วเพื่อขับเคลื่อนการทำงานที่กำหนดเองเมื่อจำเป็น ทุกคนทำเช่นเดียวกับในตัวอย่างของคุณ ปัญหาคือที่ที่ผู้คนกำลังใช้เฟรมเวิร์กทั้งหมดที่มีอยู่เพื่อจัดการสิ่งนี้อย่างหมดจดและโค้ดอย่างเคร่งครัดทุกแง่มุมของฟังก์ชั่นการใช้งานขึ้นอยู่กับฟังก์ชั่นนี้ พวกเขาเพิ่ม IReader เป็นพารามิเตอร์ในการสร้าง Sprite และท้ายที่สุดจำเป็นต้องมีวัตถุ SpriteWithFileReaderFactory พิเศษเพื่ออำนวยความสะดวกเช่นนี้เป็นต้นทัศนคตินี้เกิดจาก Java และสิ่งต่าง ๆ เช่น Spring IoC container ฯลฯ
Kylotan

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

ฉันสงสัยว่าหลายคนกำลังต่อต้าน IoC เพราะมันหมายถึง:
phtrivier

4

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


2
จะแม่นยำฉันต้องกังวลเกี่ยวกับบทลงโทษ vtable สำหรับรหัสใด ๆ ที่เรียกว่าหลาย ๆ ครั้งเฟรม สิ่งนี้อาจจะใช่หรือไม่ใช่ระดับต่ำ
tenpn

4

ต้องเห็นด้วยกับ Kylotan ในอันนี้ "การฉีดพึ่งพา" เป็นวิธีแก้ปัญหา Java ที่น่าเกลียดสำหรับข้อบกพร่องเกี่ยวกับแนวคิด Java ที่น่าเกลียดและเหตุผลเดียวที่ทุกคนมองมันเป็นภาษาอื่น ๆ ก็คือเพราะ Java กลายเป็นภาษาแรกสำหรับคนจำนวนมากเมื่อไม่ควรทำ

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

นี่คือความคิดที่มีมาตั้งแต่ปี 1950 มันอยู่ในไลบรารี่มาตรฐาน C (qsort อยู่ในใจ) และมันอยู่ทั่วสถานที่ใน Delphi และ. NET (ตัวจัดการเหตุการณ์ / ผู้ได้รับมอบหมาย) มันเปิดใช้งานรหัสเก่าที่จะเรียกรหัสใหม่โดยไม่จำเป็นต้องคอมไพล์รหัสเก่าอีกครั้งและมันจะถูกใช้ตลอดเวลาในเอ็นจิ้นเกม


2
ฉันยังเป็นของ "ดังนั้นนี่คือสิ่งที่ผู้คนตื่นเต้น?" เมื่อฉันอ่านเกี่ยวกับ DI แต่ความจริงก็คือผู้เขียนโปรแกรมเกมส่วนใหญ่สามารถยืนเพื่อเรียนรู้เกี่ยวกับมันและวิธีการที่จะนำไปใช้กับงานที่เราทำ
dash-tom-bang

2

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

อย่างไรก็ตามจะต้องมีการกล่าวว่าทั้งสองวิธีสามารถใน C ++ แนะนำตารางเสมือนที่ไม่เคยมีมาก่อนซึ่งจะนำไปสู่ประสิทธิภาพที่เหมาะสม


1

ฉันไม่ใช่นักพัฒนาเกมมืออาชีพและพยายามใช้ IoC ใน C ++ เพียงครั้งเดียวดังนั้นนี่จึงเป็นการคาดเดา

อย่างไรก็ตามฉันสงสัยว่าผู้พัฒนาเกมจะสงสัยเกี่ยวกับ IoC เพราะมันหมายถึง:

1 / ออกแบบอินเทอร์เฟซจำนวนมากและคลาสเล็ก ๆ จำนวนมาก

2 / มีการเรียกใช้ฟังก์ชันทุกครั้งที่ถูกผูกไว้เมื่อเร็ว ๆ นี้

ตอนนี้อาจเป็นเรื่องบังเอิญ แต่ทั้งคู่มีแนวโน้มที่จะซับซ้อนและ / หรือมีปัญหาเล็กน้อยสำหรับการแสดงใน C ++ (ซึ่งใช้กันอย่างแพร่หลายในเกมใช่ไหม?) มากกว่าใน Java ที่ IoC เริ่มแพร่หลาย (อาจเป็นไปได้ว่า เพราะมันค่อนข้างง่ายที่จะช่วยคนออกแบบลำดับชั้นของวัตถุ saner และเพราะบางคนเชื่อว่ามันสามารถเปลี่ยนการเขียนแอพพลิเคชั่นใน Java เป็นการเขียนแอพพลิเคชั่นใน XML แต่นั่นเป็นการอภิปรายอื่น: P)

ฉันสนใจในความคิดเห็นหากไม่ได้ทำให้รู้สึกใด ๆ เลย)

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