Mối quan tâm của anh là số lượng lớn các lớp học sẽ chuyển thành cơn ác mộng bảo trì. Quan điểm của tôi là nó sẽ có tác dụng ngược lại chính xác.
Tôi hoàn toàn đứng về phía bạn của bạn, nhưng đó có thể là vấn đề thuộc về lĩnh vực của chúng tôi và các loại vấn đề và thiết kế chúng tôi giải quyết và đặc biệt là những loại điều nào có thể yêu cầu thay đổi trong tương lai. Vấn đề khác nhau, giải pháp khác nhau. Tôi không tin đúng hay sai, chỉ là các lập trình viên cố gắng tìm ra cách tốt nhất họ có thể để giải quyết tốt nhất các vấn đề thiết kế cụ thể của họ. Tôi làm việc trong VFX, không giống với các công cụ trò chơi.
Nhưng vấn đề đối với tôi mà tôi phải vật lộn với cái mà ít nhất có thể được gọi là kiến trúc tuân thủ RẮN hơn (dựa trên COM), có thể bị luộc xuống thành "quá nhiều lớp" hoặc "quá nhiều chức năng" như bạn của bạn có thể mô tả. Tôi đặc biệt nói, "quá nhiều tương tác, quá nhiều nơi có thể xảy ra sai, quá nhiều nơi có thể gây ra tác dụng phụ, quá nhiều nơi có thể cần phải thay đổi và quá nhiều nơi không thể làm những gì chúng ta nghĩ họ làm . "
Chúng tôi đã có một số giao diện trừu tượng (và thuần túy) được triển khai bởi một nhóm các kiểu con, giống như vậy (tạo sơ đồ này trong bối cảnh nói về lợi ích của ECS, bỏ qua nhận xét phía dưới bên trái):
Trường hợp giao diện chuyển động hoặc giao diện nút cảnh có thể được thực hiện bởi hàng trăm kiểu con: đèn, máy ảnh, mắt lưới, bộ giải vật lý, đổ bóng, kết cấu, xương, hình dạng nguyên thủy, đường cong, v.v. (và thường có nhiều loại ). Và vấn đề cuối cùng là những thiết kế đó không ổn định lắm. Chúng tôi đã thay đổi các yêu cầu và đôi khi chính các giao diện phải thay đổi và khi bạn muốn thay đổi một giao diện trừu tượng được thực hiện bởi 200 kiểu con, đó là một thay đổi cực kỳ tốn kém. Chúng tôi bắt đầu giảm thiểu rằng bằng cách sử dụng các lớp cơ sở trừu tượng ở giữa giúp giảm chi phí cho những thay đổi thiết kế như vậy, nhưng chúng vẫn còn đắt đỏ.
Vì vậy, thay vào đó tôi bắt đầu khám phá kiến trúc hệ thống thành phần thực thể được sử dụng khá phổ biến trong ngành công nghiệp trò chơi. Điều đó đã thay đổi mọi thứ để được như thế này:
Và wow! Đó là một sự khác biệt về khả năng bảo trì. Các phụ thuộc không còn chảy theo trừu tượng , mà hướng tới dữ liệu (các thành phần). Và trong trường hợp của tôi, ít nhất, dữ liệu ổn định hơn và dễ dàng hơn về mặt thiết kế trả trước bất chấp các yêu cầu thay đổi (mặc dù những gì chúng ta có thể làm với cùng một dữ liệu luôn thay đổi theo yêu cầu thay đổi).
Ngoài ra, vì các thực thể trong ECS sử dụng thành phần thay vì kế thừa, chúng thực sự không cần chứa chức năng. Chúng chỉ là "thùng chứa các thành phần" tương tự. Điều đó khiến cho 200 kiểu con tương tự triển khai giao diện chuyển động biến thành 200 trường hợp thực thể (không phải các loại riêng biệt với mã riêng) chỉ lưu trữ một thành phần chuyển động (không có gì ngoài dữ liệu liên quan đến chuyển động). A PointLight
không còn là một lớp / kiểu con riêng biệt. Nó hoàn toàn không phải là một lớp học. Đây là một thực thể của một thực thể chỉ kết hợp một số thành phần (dữ liệu) liên quan đến vị trí của nó trong không gian (chuyển động) và các thuộc tính cụ thể của đèn điểm. Chức năng duy nhất liên quan đến chúng là bên trong các hệ thống, nhưRenderSystem
, tìm kiếm các thành phần ánh sáng trong cảnh để xác định cách hiển thị cảnh.
Với các yêu cầu thay đổi theo phương pháp ECS, thường chỉ cần thay đổi một hoặc hai hệ thống hoạt động trên dữ liệu đó hoặc chỉ giới thiệu một hệ thống mới ở bên cạnh hoặc giới thiệu một thành phần mới nếu cần dữ liệu mới.
Vì vậy, đối với tên miền của tôi ít nhất, và tôi gần như chắc chắn nó không dành cho tất cả mọi người, điều này làm cho mọi thứ trở nên dễ dàng hơn rất nhiều vì sự phụ thuộc đang hướng đến sự ổn định (những thứ không cần phải thay đổi thường xuyên). Đó không phải là trường hợp trong kiến trúc COM khi các phần phụ thuộc được truyền thống nhất theo hướng trừu tượng. Trong trường hợp của tôi, thật dễ dàng hơn để tìm ra dữ liệu nào là cần thiết cho chuyển động trước thay vì tất cả những điều có thể bạn có thể làm với nó, thường thay đổi một chút trong nhiều tháng hoặc nhiều năm khi có yêu cầu mới.
Có trường hợp nào trong OOP khi một số hoặc tất cả các nguyên tắc RẮN không cho vay để làm sạch mã không?
Chà, mã sạch Tôi không thể nói vì một số người đánh đồng mã sạch với RẮN, nhưng chắc chắn có một số trường hợp tách dữ liệu khỏi chức năng như ECS, và chuyển hướng phụ thuộc khỏi trừu tượng sang dữ liệu chắc chắn có thể giúp mọi việc dễ dàng hơn rất nhiều thay đổi, vì lý do khớp nối rõ ràng, nếu dữ liệu sẽ ổn định hơn rất nhiều so với trừu tượng. Tất nhiên việc phụ thuộc vào dữ liệu có thể khiến việc duy trì bất biến trở nên khó khăn, nhưng ECS có xu hướng giảm thiểu đến mức tối thiểu với tổ chức hệ thống nhằm giảm thiểu số lượng hệ thống truy cập vào bất kỳ loại thành phần nào.
Không nhất thiết là các phụ thuộc phải chuyển sang trừu tượng như DIP sẽ đề xuất; phụ thuộc nên chảy vào những thứ rất khó có thể cần thay đổi trong tương lai. Điều đó có thể hoặc không thể trừu tượng trong mọi trường hợp (nó chắc chắn không phải là của tôi).
- Có, tồn tại các nguyên tắc thiết kế OOP xung đột một phần với RẮN
- Có, tồn tại các nguyên tắc thiết kế OOP hoàn toàn mâu thuẫn với RẮN.
Tôi không chắc chắn nếu ECS thực sự là một hương vị của OOP. Một số người định nghĩa nó theo cách đó, nhưng tôi thấy nó rất khác biệt với các đặc điểm ghép nối và tách dữ liệu (các thành phần) khỏi chức năng (hệ thống) và thiếu đóng gói dữ liệu. Nếu nó được coi là một dạng của OOP, tôi sẽ nghĩ rằng nó rất mâu thuẫn với RẮN (ít nhất là những ý tưởng khắt khe nhất về SRP, mở / đóng, thay thế liskov và DIP). Nhưng tôi hy vọng đây là một ví dụ hợp lý về một trường hợp và lĩnh vực trong đó các khía cạnh cơ bản nhất của RẮN, ít nhất là mọi người thường diễn giải chúng trong bối cảnh OOP dễ nhận biết hơn, có thể không được áp dụng như vậy.
Lớp học thiếu niên
Tôi đang giải thích kiến trúc của một trong những trò chơi của tôi, trong sự ngạc nhiên của bạn tôi, có nhiều lớp nhỏ và một vài lớp trừu tượng. Tôi lập luận rằng đây là kết quả của việc tôi tập trung vào việc trao mọi thứ cho một Trách nhiệm duy nhất và cũng để nới lỏng sự ghép nối giữa các thành phần.
ECS đã thách thức và thay đổi quan điểm của tôi rất nhiều. Giống như bạn, tôi từng nghĩ rằng chính ý tưởng về khả năng duy trì là thực hiện đơn giản nhất cho những điều có thể, trong đó bao hàm nhiều điều, và hơn nữa, nhiều điều phụ thuộc lẫn nhau (ngay cả khi sự phụ thuộc lẫn nhau nằm giữa trừu tượng). Sẽ có ý nghĩa nhất nếu bạn phóng to chỉ một lớp hoặc hàm để muốn xem cách triển khai đơn giản, đơn giản nhất và nếu chúng ta không nhìn thấy một, hãy cấu trúc lại nó và thậm chí có thể phân tách nó hơn nữa. Nhưng kết quả có thể dễ dàng bỏ lỡ những gì đang xảy ra với thế giới bên ngoài, bởi vì bất cứ khi nào bạn chia bất cứ thứ gì tương đối phức tạp thành 2 hoặc nhiều thứ, thì 2 hoặc nhiều thứ đó chắc chắn phải tương tác * (xem bên dưới) với nhau trong một số cách, hoặc một cái gì đó bên ngoài phải tương tác với tất cả chúng.
Ngày nay tôi thấy có một hành động cân bằng giữa sự đơn giản của một cái gì đó và có bao nhiêu thứ và có bao nhiêu tương tác được yêu cầu. Các hệ thống trong ECS có xu hướng khá nặng nề với các triển khai không tầm thường để vận hành trên dữ liệu, như PhysicsSystem
hoặc RenderSystem
hoặc GuiLayoutSystem
. Tuy nhiên, thực tế là một sản phẩm phức tạp cần rất ít trong số chúng có xu hướng giúp dễ dàng lùi lại và suy luận về hành vi chung của toàn bộ cơ sở mã. Có một cái gì đó ở đó có thể gợi ý rằng nó có thể không phải là một ý tưởng tồi khi nghiêng về phía các lớp ít hơn, cồng kềnh hơn (vẫn thực hiện một trách nhiệm duy nhất có thể tranh cãi), nếu điều đó có nghĩa là ít lớp hơn để duy trì và lý do, và ít tương tác hơn trong suốt hệ thống.
Tương tác
Tôi nói "tương tác" chứ không phải "khớp nối" (mặc dù giảm tương tác ngụ ý giảm cả hai), vì bạn có thể sử dụng trừu tượng để tách rời hai đối tượng cụ thể, nhưng chúng vẫn nói chuyện với nhau. Họ vẫn có thể gây ra tác dụng phụ trong quá trình giao tiếp gián tiếp này. Và thường thì tôi thấy khả năng suy luận về tính đúng đắn của một hệ thống có liên quan đến những "tương tác" này hơn là "khớp nối". Giảm thiểu các tương tác có xu hướng làm cho mọi thứ dễ dàng hơn đối với tôi để suy luận về mọi thứ từ góc nhìn của một con chim. Điều đó có nghĩa là mọi thứ hoàn toàn không nói chuyện với nhau, và từ ý nghĩa đó, ECS cũng có xu hướng thực sự giảm thiểu "tương tác", và không chỉ khớp nối, đến mức tối thiểu (ít nhất là tôi trốn tránh '
Điều đó nói rằng, điều này có thể ít nhất một phần là tôi và điểm yếu cá nhân của tôi. Tôi đã tìm thấy trở ngại lớn nhất đối với tôi khi tạo ra các hệ thống có quy mô khổng lồ, và vẫn tự tin lý luận về chúng, điều hướng qua chúng và cảm thấy như tôi có thể thực hiện bất kỳ thay đổi mong muốn tiềm năng nào ở bất cứ đâu theo cách có thể dự đoán được, đó là quản lý tài nguyên và nhà nước cùng với tác dụng phụ. Đó là trở ngại lớn nhất bắt đầu nảy sinh khi tôi đi từ hàng chục ngàn LỘC đến hàng trăm ngàn LỘC đến hàng triệu LỘC, ngay cả đối với mã mà tôi tự tạo hoàn toàn. Nếu một cái gì đó sẽ làm tôi chậm lại để bò lên trên tất cả những thứ khác, thì có nghĩa là tôi không còn có thể hiểu những gì đang xảy ra về trạng thái ứng dụng, dữ liệu, tác dụng phụ. Nó ' Đây không phải là thời gian robot cần thiết để tạo ra sự thay đổi khiến tôi chậm lại nhiều đến mức không thể hiểu được toàn bộ tác động của thay đổi nếu hệ thống phát triển vượt quá khả năng suy nghĩ của tôi về nó. Và đối với tôi, việc giảm các tương tác là cách hiệu quả nhất để cho phép sản phẩm phát triển lớn hơn nhiều với nhiều tính năng hơn mà cá nhân tôi không bị choáng ngợp bởi những điều này, vì giảm tương tác xuống mức tối thiểu cũng làm giảm số lượng địa điểm có thể thậm chí có thể thay đổi trạng thái ứng dụng và gây ra tác dụng phụ đáng kể.
Nó có thể biến một thứ như thế này (trong đó mọi thứ trong sơ đồ đều có chức năng, và rõ ràng một kịch bản trong thế giới thực sẽ có số lượng đối tượng nhiều, gấp nhiều lần và đây là sơ đồ "tương tác", chứ không phải khớp nối, như một khớp nối người ta sẽ có sự trừu tượng ở giữa):
... đến đây, nơi chỉ có các hệ thống có chức năng (các thành phần màu xanh bây giờ chỉ là dữ liệu và bây giờ đây là sơ đồ khớp nối):
Và có những suy nghĩ xuất hiện trên tất cả những điều này và có thể là một cách để đóng khung một số lợi ích này trong bối cảnh OOP phù hợp hơn, tương thích hơn với RẮN, nhưng tôi vẫn chưa tìm thấy các thiết kế và từ ngữ, và tôi thấy nó khó khăn vì thuật ngữ này tôi đã quen với tất cả những gì liên quan trực tiếp đến OOP. Tôi tiếp tục cố gắng tìm ra cách đọc qua câu trả lời của mọi người ở đây và cũng cố gắng hết sức để tự mình xây dựng, nhưng có một số điều rất thú vị về bản chất của một ECS mà tôi không thể đặt ngón tay của mình lên đó có thể được áp dụng rộng rãi hơn ngay cả đối với các kiến trúc không sử dụng nó. Tôi cũng hy vọng câu trả lời này không xuất hiện dưới dạng khuyến mãi của ECS! Tôi chỉ thấy nó rất thú vị vì thiết kế một ECS đã thực sự thay đổi suy nghĩ của tôi,