Các trò chơi bán lẻ có sử dụng đảo ngược điều khiển và điều khiển phụ thuộc vào cộng đồng hay không?


30

Nhiều nhà phát triển phần mềm siêng năng hơn mà tôi biết đang chuyển sang nghịch đảo kiểm soáttiêm phụ thuộc để xử lý các tham chiếu đến các đối tượng. Xuất phát từ góc độ trò chơi Flash, tôi không biết tất cả các hãng phim AAA, vì vậy: chúng có được sử dụng trong thế giới trò chơi bán lẻ không?


Tôi nghĩ rằng trong hiệu suất thế giới đó là vấn đề quan trọng hơn cả, vì nhiều người dùng sẽ bị ảnh hưởng bởi hiệu suất thấp hơn so với các lập trình viên bởi mã xấu.
Bart van Heukelom

Việc tiêm phụ thuộc nghe có vẻ giống như một hệ thống dựa trên thành phần, nhưng bạn sẽ có một ví dụ về cách người ta sẽ đảo ngược sự kiểm soát?
ADB

Vì hầu hết các chủ đề này dường như bị hiểu sai về IoC là gì và nó giải quyết được gì và OP không thực sự hỏi rằng ở nơi đầu tiên tôi sẽ chỉ ra cho khách truy cập trong tương lai: sebaslab.com/ioc-container-unity-part-1
Boris Callens

Vâng, họ làm. Trên thực tế, Rare đã có một cuộc nói chuyện về cách họ đang thực hiện thử nghiệm của mình trong Sea of ​​Thief - youtube.com/watch?v=KmaGxprTUfI&t=1s . Thật không may, họ không có quá nhiều điều để nói về Inversion of Control trong Unreal Engine, tuy nhiên, tôi đã viết một dự án chứng minh cách thức hoạt động của nó: github.com/jimmyt1988/UE-Testing
Jimmyt1988

Câu trả lời:


45

Bạn gọi nó là 'phát triển phần mềm siêng năng', tôi gọi đó là 'sự áp đảo đau đớn'. Điều đó không có nghĩa là sự đảo ngược của kiểm soát là xấu - trên thực tế, định nghĩa cơ bản của nó là tốt - nhưng sự phổ biến của toàn bộ khuôn khổ và phương pháp làm việc để đạt được tất cả điều này là hơi điên rồ, đặc biệt là kết hợp với cách mọi người đang dọn rác giao diện hoàn toàn tốt và sạch sẽ để có thể tiêm các thành phần có thể hoán đổi cho nhau mà 99% thời gian bạn sẽ không bao giờ trao đổi. Đó là thứ chỉ có thể bắt nguồn từ môi trường doanh nghiệp Java và tôi rất vui vì nó không có nhiều chỗ đứng ở nơi khác.

Thông thường, đối số là ngay cả khi bạn không trao đổi các thành phần, bạn muốn có thể kiểm tra chúng một cách cô lập với các đối tượng giả và tương tự. Tuy nhiên, tôi e rằng tôi sẽ không bao giờ mua lập luận rằng nó đáng để làm đầy và làm phức tạp một giao diện để có thể kiểm tra nó tốt hơn. Kiểm tra chứng minh một điều duy nhất - rằng các thử nghiệm của bạn hoạt động. Mặt khác, các giao diện sạch và tối thiểu đi một chặng đường dài để chứng minh rằng mã của bạn hoạt động.

Vì vậy, câu trả lời ngắn gọn: có, nhưng không phải theo cách bạn đang nghĩ. Đôi khi, khi bạn cần hành vi có thể hoán đổi cho nhau, bạn sẽ chuyển một đối tượng đến một nhà xây dựng chỉ đạo một phần hành vi của đối tượng mới. Đó là về nó.


5
+1 - Tôi đồng ý rằng cộng đồng Java dường như quá phức tạp, điều dường như là một ý tưởng rất đơn giản.
Chris Howe

4
Ý tưởng không nhất thiết là bạn sẽ cần trao đổi các triển khai khác nhau trong sản xuất, nhưng bạn có thể muốn thực hiện các triển khai đặc biệt để tạo điều kiện cho thử nghiệm tự động. Về vấn đề đó, DI / IoC chắc chắn có thể hữu ích trong các trò chơi, nhưng bạn muốn giữ nó trong phạm vi hợp lý. Bạn không cần nhiều hơn một vài độ phân giải dịch vụ một lần ở mức cao - bạn không muốn giải quyết các dịch vụ cho mọi đối tượng nhỏ trong trò chơi và chắc chắn không phải mọi khung hình hay bất cứ thứ gì tương tự.
Mike Strobel

2
@Thomas Dufour: khái niệm về một bài kiểm tra không bao giờ có thể chứng minh bất cứ điều gì. Nó chỉ là một điểm dữ liệu. Bạn có thể vượt qua bài kiểm tra 100000 lần mà không cần chứng minh rằng nó sẽ vượt qua khi chạy 100001. Bằng chứng đến từ phân tích logic của vấn đề. Tôi sẽ lập luận rằng các thùng chứa IoC này và những thứ tương tự làm cho việc kiểm tra dễ dàng hơn với chi phí làm cho việc chứng minh tính đúng đắn trở nên khó khăn hơn và tôi tin rằng đó là một điều tồi tệ.
Kylotan

13
@Kylotan khái niệm về một bài kiểm tra không bao giờ cố gắng chứng minh bất cứ điều gì. Nó cố gắng chứng minh rằng hành vi với các đầu vào đã cho là như mong đợi. Càng nhiều hành vi được hiển thị là chính xác, bạn càng tin rằng chức năng tổng thể là chính xác nhưng nó không bao giờ 100%. Tuyên bố rằng một giao diện tối thiểu chứng minh bất cứ điều gì là lố bịch.
dash-tom-bang

5
@Alex Schearer: Tôi e rằng tôi không bao giờ chấp nhận rằng cần phải sử dụng hệ thống bộ chứa IoC chính thức và thường tạo thêm các đối số hàm tạo hoặc các lớp nhà máy để tạo điều kiện cho việc kiểm tra, theo cách nào đó, làm cho mã được xác thực tốt hơn, và chắc chắn là không làm cho nó lỏng lẻo kết hợp. Trong thực tế, nó khá nhiều chà đạp về đóng gói, một khía cạnh quan trọng của OOP. Thay vì dựa vào TDD để thúc đẩy thiết kế của họ và hy vọng rằng một kết quả tốt sẽ xuất hiện, mọi người chỉ có thể tuân theo các nguyên tắc RẮN ngay từ đầu.
Kylotan

17

Mô hình chiến lược , Thành phần , Tiêm phụ thuộc , tất cả đều liên quan rất chặt chẽ.

Vì Mô hình Chiến lược là một hình thức của Dependency Injection, nếu bạn xem các công cụ như Unity chẳng hạn, chúng hoàn toàn dựa trên nguyên tắc này. Việc sử dụng Thành phần (Mẫu chiến lược) của họ được nhúng sâu vào toàn bộ công cụ của họ.

Một trong những lợi ích chính ngoài việc tái sử dụng các thành phần là tránh các hệ thống phân cấp lớp sâu đáng sợ.

Dưới đây là một bài viết của Mick West , người nói về cách ông giới thiệu loại hệ thống này vào loạt trò chơi Tony Hawk của Neversoft.

Phát triển thứ bậc của bạn

Cho đến những năm gần đây, các lập trình viên trò chơi đã liên tục sử dụng một hệ thống phân cấp lớp sâu để đại diện cho các thực thể trò chơi. Làn sóng đang bắt đầu chuyển từ việc sử dụng hệ thống phân cấp sâu này sang nhiều phương thức khác nhau tạo thành một đối tượng thực thể trò chơi như một tập hợp của các thành phần ...


2
+1, Phát triển thứ bậc của bạn là một liên kết tuyệt vời mà tôi hoàn toàn quên mất. Các slide của Scott Bilas cũng tốt - liên kết chính xác cho các slide này là ( scottbilas.com/files/2002/gdc_san_jose/game_objects_slides.pdf ). Có một thiết lập nhiều hơn các slide có liên quan, nhưng tôi đã quên nơi ...
leander

Ngoài ra bài viết trong Games Gems 5 (tôi nghĩ) của Bjarne Rene.
Chris Howe

13

Dường như có rất nhiều nhầm lẫn về mẫu Inversion of Control (IoC). Một số người đã đánh đồng nó với Mô hình chiến lược hoặc Mô hình thành phần, nhưng những so sánh này không thực sự nắm bắt được IoC là gì. IoC thực sự là về cách thu được một sự phụ thuộc. Tôi sẽ cho bạn một ví dụ:

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
    }
}

Ở trên, rõ ràng Sprite.Loadcó sự phụ thuộc vào a FileReader. Khi bạn muốn kiểm tra phương pháp bạn cần như sau:

  1. Một hệ thống tập tin tại chỗ
  2. Một tệp thử nghiệm để tải từ hệ thống tệp
  3. Khả năng kích hoạt các lỗi hệ thống tệp phổ biến

Hai cái đầu tiên là rõ ràng, nhưng nếu bạn muốn đảm bảo rằng việc xử lý lỗi của bạn hoạt động như mong đợi, bạn cũng thực sự cần số 3. Trong cả hai trường hợp, bạn có khả năng làm chậm các bài kiểm tra của mình xuống một chút vì bây giờ chúng cần phải vào đĩa và bạn có thể làm cho môi trường kiểm tra của bạn phức tạp hơn.

Mục tiêu của IoC là tách rời việc sử dụng hành vi từ việc xây dựng nó. Lưu ý cách này khác với mẫu Chiến lược. Với mẫu Chiến lược, mục tiêu là gói gọn một đoạn hành vi có thể sử dụng lại để bạn có thể dễ dàng mở rộng nó trong tương lai; nó không có gì để nói về cách các chiến lược được xây dựng.

Nếu chúng ta viết lại Sprite.Loadphương thức trên, chúng ta có thể sẽ kết thúc bằng:

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

Bây giờ, chúng tôi đã tách rời việc xây dựng của người đọc từ việc sử dụng nó. Do đó, có thể trao đổi trong một trình đọc thử trong khi thử nghiệm. Điều này có nghĩa là môi trường kiểm tra của bạn không còn cần một hệ thống tệp, tệp kiểm tra và có thể dễ dàng mô phỏng các sự kiện lỗi.

Lưu ý rằng tôi đã làm hai điều trong bản viết lại của mình. Tôi đã tạo một giao diện IReadergói gọn một số hành vi - tức là đã triển khai mẫu Chiến lược. Ngoài ra, tôi chuyển trách nhiệm tạo độc giả phù hợp sang một lớp khác.

Có lẽ chúng ta không cần một tên mẫu mới để mô tả ở trên. Nó tạo cho tôi một sự pha trộn giữa các mẫu Chiến lược và Nhà máy (đối với các thùng chứa IoC). Điều đó đang được nói, tôi không chắc chắn về lý do mọi người phản đối mô hình này vì rõ ràng nó giải quyết được một vấn đề thực sự và chắc chắn, đối với tôi điều này không rõ ràng với Java.


2
Alex: không ai phản đối việc chuyển vào các đối tượng đã được tạo để điều khiển chức năng tùy chỉnh khi cần thiết. Mọi người đều làm điều đó, giống như trong ví dụ của bạn. Vấn đề là ở chỗ mọi người đang sử dụng toàn bộ các khung tồn tại hoàn toàn để xử lý công cụ này và mã hóa mọi khía cạnh của chức năng để phụ thuộc vào chức năng này. Trước tiên, họ thêm IReader làm tham số cho việc xây dựng Sprite và sau đó cuối cùng cần các đối tượng SpriteWithFileReaderFactory đặc biệt để tạo điều kiện thuận lợi cho việc này, v.v. Thái độ này bắt nguồn từ Java và những thứ như các thùng chứa Spring IoC, v.v.
Kylotan

2
Nhưng chúng ta không nói về các container IoC - ít nhất là tôi không thấy nó trong bài viết gốc. Chúng ta chỉ nói về mô hình chính nó. Bạn tranh luận, tốt nhất tôi có thể nói, là "Bởi vì một số công cụ trong tự nhiên là xấu, chúng ta không nên sử dụng các khái niệm cơ bản." Điều đó đánh tôi như ném em bé ra ngoài bằng nước tắm. Đánh vào sự cân bằng hợp lý giữa sự đơn giản, hoàn thành công việc và khả năng duy trì / kiểm tra là một vấn đề khó có thể được xử lý tốt nhất trên một dự án theo dự án.
Alex Schearer

Tôi nghi ngờ nhiều người chống lại IoC bởi vì nó có nghĩa là:
phtrivier

4

Tôi có thể nói rằng nó là một công cụ trong số rất nhiều, và nó được sử dụng đôi khi. Như tenpn đã nói, bất kỳ phương pháp nào giới thiệu vtables (và nói chung là bất kỳ sự gián tiếp bổ sung nào) đều có thể bị phạt hiệu năng, nhưng đây là điều mà chúng ta chỉ nên lo lắng về mã cấp thấp. Đối với mã cấu trúc cấp cao không thực sự là vấn đề và IoC có thể có lợi ích tích cực. Bất cứ điều gì để giảm sự phụ thuộc giữa các lớp và làm cho mã của bạn linh hoạt hơn.


2
Nói chính xác, tôi lo lắng về các hình phạt vtable cho bất kỳ mã nào được gọi nhiều lần trong một khung. Điều này có thể hoặc không thể ở mức độ thấp.
tenpn

4

Gotta đồng ý với Kylotan về điều này. "Tiêm phụ thuộc" là một giải pháp Java xấu cho lỗ hổng khái niệm Java xấu xí và lý do duy nhất bất cứ ai nhìn vào nó bằng các ngôn ngữ khác là vì Java trở thành ngôn ngữ đầu tiên cho nhiều người, khi nó thực sự không nên.

Mặt khác, kiểm soát đảo ngược là một ý tưởng hữu ích đã có từ lâu và rất hữu ích khi được thực hiện đúng. (Không phải cách Java / Dependency Injection.) Trên thực tế, bạn có thể làm điều đó mọi lúc nếu bạn đang làm việc trong một ngôn ngữ lập trình lành mạnh. Khi tôi lần đầu tiên đọc về toàn bộ điều "IOC" này, mọi người đều xôn xao, tôi hoàn toàn bị choáng ngợp. Inversion of Control không gì khác hơn là chuyển một con trỏ hàm (hoặc con trỏ phương thức) đến một thường trình hoặc đối tượng để giúp tùy chỉnh hành vi của nó.

Đây là một ý tưởng đã có từ những năm 1950. Nó nằm trong thư viện chuẩn C (qsort hiện lên trong tâm trí) và nó ở khắp mọi nơi trong Delphi và .NET (xử lý sự kiện / đại biểu). Nó cho phép mã cũ gọi mã mới mà không cần biên dịch lại mã cũ và nó được sử dụng mọi lúc trong các công cụ trò chơi.


2
Tôi cũng là của "vì vậy đây là những gì mọi người đang vui mừng về?" Khi tôi đọc về DI, nhưng thực tế là hầu hết các lập trình viên trò chơi có thể đứng để tìm hiểu về nó và về cách nó sẽ áp dụng cho công việc chúng tôi làm.
dash-tom-bang

2

Không theo kinh nghiệm của tôi. Đó là một sự xấu hổ, vì mã trò chơi cần phải rất dễ thích nghi, và những cách tiếp cận này chắc chắn sẽ giúp ích.

Tuy nhiên, phải nói rằng cả hai phương thức đều có thể, trong C ++, giới thiệu các bảng ảo mà trước đó không có phương thức nào, mang lại cho chúng một hiệu năng phù hợp.


1

Tôi không phải là một nhà phát triển game chuyên nghiệp và chỉ thử triển khai IoC trong C ++ một lần, vì vậy đây chỉ là suy đoán.

Tuy nhiên, tôi nghi ngờ các nhà phát triển trò chơi sẽ nghi ngờ về IoC bởi vì điều đó có nghĩa là:

1 / thiết kế nhiều giao diện và nhiều lớp nhỏ

2 / có khá nhiều cuộc gọi chức năng bị ràng buộc gần đây

Bây giờ, nó có thể là một sự trùng hợp ngẫu nhiên, nhưng cả hai đều có xu hướng phức tạp hơn một chút và / hoặc có vấn đề đối với các màn trình diễn trong C ++ (được sử dụng rộng rãi trong trò chơi, phải không?) So với Java, nơi IoC trở nên phổ biến (Có lẽ là bởi vì nó tương đối dễ thực hiện, giúp mọi người thiết kế hệ thống phân cấp đối tượng saner và vì một số người tin rằng nó có thể biến việc viết một ứng dụng trong Java thành viết một ứng dụng bằng XML, nhưng đó là một cuộc tranh luận khác: P)

Tôi quan tâm đến các bình luận nếu điều đó không có ý nghĩa gì cả;)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.