Là đối tượng kiến ​​trúc hệ thống thành phần thực thể được định hướng theo định nghĩa?


20

Là đối tượng kiến trúc hệ thống thành phần thực thể được định hướng, theo định nghĩa? Nó có vẻ nhiều thủ tục hoặc chức năng đối với tôi. Ý kiến ​​của tôi là nó không ngăn bạn thực hiện nó bằng ngôn ngữ OO, nhưng sẽ không thành công nếu làm theo cách OO một cách kiên quyết.

Có vẻ như ECS tách dữ liệu (E & C) khỏi hành vi (S). Bằng chứng là :

Ý tưởng là không có phương thức trò chơi nào được nhúng trong thực thể.

:

Thành phần này bao gồm một tập hợp dữ liệu tối thiểu cần thiết cho một mục đích cụ thể

Hệ thống là các hàm đơn mục đích có một tập hợp các thực thể có một thành phần cụ thể


Tôi nghĩ rằng đây không phải là hướng đối tượng bởi vì một phần lớn của việc hướng đối tượng là kết hợp dữ liệu và hành vi của bạn với nhau. Bằng chứng là :

Ngược lại, cách tiếp cận hướng đối tượng khuyến khích lập trình viên đặt dữ liệu ở nơi mà phần còn lại của chương trình không thể truy cập trực tiếp. Thay vào đó, dữ liệu được truy cập bằng cách gọi các hàm được viết đặc biệt, thường được gọi là các phương thức, được gói cùng với dữ liệu.

ECS, mặt khác, dường như là tất cả về việc tách dữ liệu của bạn khỏi hành vi của bạn.

Câu trả lời:


21

Giới thiệu


Các hệ thống thành phần Entity vào là một kỹ thuật kiến ​​trúc hướng đối tượng.

Không có sự đồng thuận phổ quát về ý nghĩa của thuật ngữ này, giống như lập trình hướng đối tượng. Tuy nhiên, rõ ràng là hệ thống tổ chức thành phần nhằm mục đích cụ thể như một sự thay thế kiến trúc để thừa kế . Hệ thống phân cấp kế thừa là tự nhiên để thể hiện đối tượng là gì , nhưng trong một số loại phần mềm nhất định (như trò chơi), bạn muốn thể hiện những gì đối tượng làm .

Đó là một mô hình đối tượng khác với các lớp và kế thừa, một mô hình mà bạn rất quen thuộc khi làm việc trong C ++ hoặc Java. Các thực thể có tính biểu cảm như các lớp, giống như các nguyên mẫu như trong JavaScript hoặc Self Nam, tất cả các hệ thống này có thể được triển khai theo các khía cạnh khác.

 

Ví dụ


Hãy nói rằng Playerlà một thực thể có Position, VelocityKeyboardControlledcác thành phần, mà làm những điều hiển nhiên.

entity Player:
  Position
  Velocity
  KeyboardControlled

Chúng tôi biết Positionphải bị ảnh hưởng bởi Velocity, và Velocitybởi KeyboardControlled. Câu hỏi là làm thế nào chúng ta muốn mô hình hóa các hiệu ứng đó.

 

Các thực thể, thành phần và hệ thống


Giả sử rằng các thành phần không có tham chiếu với nhau; một Physicshệ thống bên ngoài đi qua tất cả các Velocitythành phần và cập nhật Positionthực thể tương ứng; một Inputhệ thống đi qua tất cả các KeyboardControlledthành phần và cập nhật Velocity.

          Player
         +--------------------+
         | Position           | \
         |                    |  Physics
       / | Velocity           | /
  Input  |                    |
       \ | KeyboardControlled |
         +--------------------+

Điều này thỏa mãn các tiêu chí:

  • Không có logic trò chơi / kinh doanh được thể hiện bởi các thực thể.

  • Các thành phần lưu trữ dữ liệu mô tả hành vi.

Các hệ thống hiện chịu trách nhiệm xử lý các sự kiện và ban hành hành vi được mô tả bởi các thành phần. Họ cũng chịu trách nhiệm xử lý các tương tác giữa các thực thể, chẳng hạn như va chạm.

 

Các thực thể và thành phần


Tuy nhiên, giả sử rằng các thành phần làm có tài liệu tham khảo với nhau. Bây giờ thực thể chỉ đơn giản là một hàm tạo tạo ra một số thành phần, liên kết chúng lại với nhau và quản lý vòng đời của chúng:

class Player:
  construct():
    this.p = Position()
    this.v = Velocity(this.p)
    this.c = KeyboardControlled(this.v)

Bây giờ thực thể có thể gửi các sự kiện đầu vào và cập nhật trực tiếp đến các thành phần của nó. Velocitysẽ trả lời các bản cập nhật và KeyboardControlledsẽ trả lời đầu vào. Điều này vẫn đáp ứng các tiêu chí của chúng tôi:

  • Thực thể này là một thùng chứa dumbal mà chỉ chuyển tiếp các sự kiện đến các thành phần.

  • Mỗi thành phần ban hành hành vi riêng của mình .

Ở đây các tương tác thành phần là rõ ràng, không bị áp đặt từ bên ngoài bởi một hệ thống. Dữ liệu mô tả một hành vi (lượng vận tốc là bao nhiêu?) Và mã ban hành nó (vận tốc là gì?) Được ghép nối, nhưng theo kiểu tự nhiên. Dữ liệu có thể được xem như là tham số cho hành vi. Và một số thành phần không hành động ở tất cả các khu vực a Positionlà hành vi ở một nơi .

Các tương tác có thể được xử lý ở cấp độ của thực thể ( PlayerHồi khi va chạm với một Tấn vụ Enemy) hoặc ở cấp độ của các thành phần riêng lẻ (Hồi khi một thực thể có Lifeva chạm với một thực thể với Hồi phạm Strength).

 

Các thành phần


Lý do cho các thực thể tồn tại là gì? Nếu nó chỉ là một hàm tạo, thì chúng ta có thể thay thế nó bằng một hàm trả về một tập hợp các thành phần. Nếu sau này chúng ta muốn truy vấn các thực thể theo loại của chúng, chúng ta cũng có thể có một Tagthành phần cho phép chúng ta làm điều đó:

function Player():
  t = Tag("Player")
  p = Position()
  v = Velocity(p)
  c = KeyboardControlled(v)
  return {t, p, v, c}
  • Các thực thể câm lặng như có thể là họ, họ chỉ là một bộ các thành phần.

  • Các thành phần phản ứng trực tiếp với các sự kiện như trước đây.

Các tương tác bây giờ phải được xử lý bằng các truy vấn trừu tượng, tách hoàn toàn các sự kiện từ các loại thực thể. Không có nhiều loại thực thể để truy vấn Tagdữ liệu tùy ý có lẽ được sử dụng để gỡ lỗi tốt hơn logic trò chơi.

 

Phần kết luận


Các thực thể không phải là chức năng, quy tắc, tác nhân hoặc tổ hợp dataflow. Chúng là những danh từ mô hình hiện tượng cụ thể, nói cách khác, chúng là đối tượng. Nó giống như Wikipedia nói rằng các hệ thống thành phần của LinkedIn là một mô hình kiến ​​trúc phần mềm để mô hình hóa các đối tượng chung.


2
Sự thay thế chính cho OO dựa trên lớp, OO dựa trên nguyên mẫu, dường như cũng kết hợp dữ liệu và hành vi. Trên thực tế, nó dường như khác với ECS cũng giống như OO dựa trên lớp học. Vì vậy, bạn có thể giải thích những gì bạn có ý nghĩa của OO?

Để thêm vào câu hỏi của @ delnan, bạn có không đồng ý với đoạn trích của bài viết wikipedia OO tôi đã trích dẫn không?
Daniel Kaplan

@tieTYT: Trích dẫn Wikipedia đang nói về việc đóng gói và che giấu thông tin. Tôi không nghĩ rằng đó là bằng chứng cho thấy việc ghép hành vi dữ liệu là bắt buộc, chỉ có điều đó là phổ biến.
Jon Purdy

@delnan: Tôi không có ý gì với OO. Đối với tôi, lập trình hướng đối tượng là chính xác những gì nó nói trên tin: lập trình với các đối tượng, (trái ngược với chức năng, quy tắc, tác nhân, tổ hợp dataflow, v.v.) trong đó định nghĩa cụ thể của đối tượng được xác định theo thực thi.
Jon Purdy

1
@tieTYT: Tôi chỉ mô tả các triển khai mà tôi đã thấy trong tự nhiên, để truyền đạt rằng đó là một thuật ngữ rộng rãi không mâu thuẫn với, nhưng chắc chắn rộng hơn mô tả Wikipedia.
Jon Purdy

20

KHÔNG. Và tôi ngạc nhiên khi có nhiều người bình chọn khác!

Mô hình

Đó là hướng dữ liệu hay còn gọi là hướng dữ liệu bởi vì chúng ta đang nói về kiến trúc chứ không phải ngôn ngữ mà nó được viết. Kiến trúc là sự hiện thực hóa các phong cách lập trình hoặc mô hình , thường có thể được làm việc một cách không mong muốn trong một ngôn ngữ nhất định.


Chức năng?

So sánh của bạn với lập trình Chức năng / Thủ tục là một so sánh có liên quan và có ý nghĩa. Tuy nhiên, lưu ý rằng ngôn ngữ "Chức năng" khác với mô hình "Thủ tục" . Và bạn có thể triển khai ECS bằng ngôn ngữ Chức năng như Haskell , điều mà mọi người đã làm.


Sự gắn kết xảy ra ở đâu

Quan sát của bạn có liên quan và tại chỗ :

"... [ECS] không ngăn bạn triển khai nó bằng ngôn ngữ OO, nhưng sẽ không thành công nếu làm theo cách OO một cách kiên quyết"


ECS / ES không phải là EC / CE

Có một sự khác biệt giữa các kiến ​​trúc dựa trên thành phần, "Thực thể-Thành phần" và "Thực thể-Thành phần-Hệ thống". Vì đây là một mẫu thiết kế đang phát triển, tôi đã thấy các định nghĩa này được sử dụng thay thế cho nhau. Kiến trúc "EC" hoặc "CE" hoặc "Thành phần thực thể" đặt hành vi trong các thành phần , trong khi kiến trúc "ES" hoặc "ECS" đặt hành vi trong các hệ thống . Dưới đây là một số bài viết của ECS, cả hai đều sử dụng danh pháp sai lệch, nhưng có được ý tưởng chung:

Nếu bạn đang cố gắng hiểu các thuật ngữ này trong năm 2015, hãy đảm bảo rằng ai đó tham khảo "Hệ thống thành phần thực thể" không có nghĩa là "Kiến trúc thành phần thực thể".


1
Đây là câu trả lời chính xác. ECS không phù hợp lắm với mô hình OOP, bởi vì ECS hoàn toàn tách biệt dữ liệu và hành vi, trong khi OOP thì ngược lại.
Nax 'vi-vim-nvim'

"Trong khi OOP thì ngược lại" Không có định nghĩa được chấp nhận về những gì OOP nói về, trừ khi các định nghĩa học thuật vô dụng như SmallTalk không bao giờ được sử dụng trong thực tế.
Jean-Michaël Celerier

10

Các hệ thống thành phần thực thể (ECS) có thể được lập trình theo OOP hoặc theo cách chức năng tùy thuộc vào cách xác định hệ thống.

Cách OOP:

Tôi đã làm việc trên các trò chơi trong đó một thực thể là một đối tượng bao gồm các thành phần khác nhau. Thực thể có chức năng cập nhật sửa đổi đối tượng tại chỗ bằng cách gọi cập nhật lần lượt trên tất cả các thành phần của nó. Đây rõ ràng là OOP theo phong cách - hành vi được liên kết với dữ liệu và dữ liệu có thể thay đổi. Các thực thể là các đối tượng với các hàm tạo / hàm hủy / cập nhật.

Cách chức năng hơn:

Một thay thế là cho thực thể là dữ liệu mà không có bất kỳ phương pháp nào. Thực thể này có thể tồn tại theo đúng nghĩa của nó hoặc đơn giản là một id được liên kết với các thành phần khác nhau. Bằng cách này, có thể (nhưng không thường được thực hiện) có đầy đủ chức năng và có các thực thể bất biến và các hệ thống thuần túy tạo ra các trạng thái thành phần mới.

Dường như (từ kinh nghiệm cá nhân) rằng cách thứ hai đang đạt được nhiều lực kéo hơn và vì lý do chính đáng. Tách dữ liệu thực thể khỏi hành vi dẫn đến mã linh hoạt hơn và có thể sử dụng lại (imo). Cụ thể, việc sử dụng các hệ thống để cập nhật các thành phần / thực thể theo đợt có thể hiệu quả hơn và tránh hoàn toàn sự phức tạp của nhắn tin liên thực thể gây ra nhiều OOP ECS.

TLDR: Bạn có thể làm theo bất kỳ cách nào, nhưng tôi sẽ lập luận rằng lợi ích của các hệ thống thành phần thực thể tốt xuất phát từ bản chất chức năng hơn của chúng.


Lực kéo nhiều hơn đặc biệt là vì toàn bộ điểm của các thành phần là để thoát khỏi hệ thống phân cấp OOP khó hiểu, mô tả tốt về lợi ích.
Patrick Hughes

2

Các hệ thống thành phần thực thể hướng dữ liệu có thể cùng tồn tại với các mô hình hướng đối tượng: - Các hệ thống thành phần cho vay để đa hình hóa. - Các thành phần có thể là cả POD (dữ liệu cũ đơn giản) và Đối tượng ALSO (với Lớp và Phương thức) và toàn bộ vẫn là "định hướng dữ liệu", với điều kiện Phương thức lớp thành phần chỉ thao tác dữ liệu do đối tượng cục bộ sở hữu.

Nếu bạn chọn đường dẫn này, tôi khuyên bạn nên tránh sử dụng Phương thức ảo, vì nếu bạn có chúng, thành phần của bạn không còn là dữ liệu thành phần đơn thuần, cộng với các phương thức đó tốn nhiều tiền hơn để gọi - đây không phải là COM. Giữ các lớp thành phần của bạn sạch sẽ khỏi mọi tham chiếu đến bất cứ thứ gì bên ngoài, như một quy luật.

Ví dụ sẽ là vec2 hoặc vec3, một thùng chứa dữ liệu với một số phương thức để chạm vào dữ liệu đó và không có gì khác.


2
bài này khá khó đọc (tường văn bản). Bạn có phiền chỉnh sửa ing nó thành một hình dạng tốt hơn? Ngoài ra, sẽ hữu ích nếu bạn giải thích cho độc giả lý do tại sao họ có thể thấy bài viết trên blog được liên kết hữu ích và phù hợp với câu hỏi được hỏi ...
gnat

... trong trường hợp nếu bạn bằng cách nào đó có liên quan đến blog đó (bạn phải không?), Bạn cũng nên tiết lộ liên kết
gnat

Vâng, đó là blog của tôi, tôi liên kết chặt chẽ với blog công khai của mình, nó tiết lộ chi tiết về hệ thống thành phần thực thể hướng đối tượng dựa trên các nguyên tắc thiết kế hướng dữ liệu, mà tôi tin là có liên quan và có thể hữu ích, dù sao tôi đã gỡ bỏ liên kết đến loại bỏ bất kỳ sự thiên vị.
Homer

2

Tôi nghĩ về ECS về cơ bản là khác biệt với OOP và có xu hướng thấy nó giống như cách bạn làm, gần với chức năng hoặc đặc biệt là về mặt thủ tục với sự phân tách dữ liệu rất khác biệt với chức năng. Ngoài ra còn có một số mối quan hệ để lập trình một loại đối phó với cơ sở dữ liệu trung tâm. Tất nhiên tôi là người tồi tệ nhất khi nói đến định nghĩa chính thức. Tôi chỉ quan tâm đến việc mọi thứ có xu hướng như thế nào chứ không phải những gì chúng được định nghĩa theo khái niệm.

Tôi đang giả sử một loại ECS nơi các thành phần tổng hợp các trường dữ liệu và làm cho chúng có thể truy cập công khai / toàn cầu, các thành phần tổng hợp các thực thể và các hệ thống cung cấp chức năng / hành vi trên dữ liệu đó. Điều đó dẫn đến các đặc điểm kiến ​​trúc cực kỳ khó khăn từ cái mà chúng ta thường gọi là một cơ sở mã hướng đối tượng.

Và tất nhiên, có một số ranh giới mờ nhạt trong cách mọi người thiết kế / thực hiện ECS, và có tranh luận về những gì chính xác cấu thành một ECS ở nơi đầu tiên. Tuy nhiên, các ranh giới như vậy cũng được làm mờ trong mã được viết bằng ngôn ngữ thủ tục hoặc chức năng. Trong số tất cả sự mờ nhạt này, hằng số cơ bản của một ECS với sự phân tách dữ liệu khỏi chức năng dường như gần với lập trình chức năng hoặc thủ tục hơn đối với tôi so với OOP.

Một trong những lý do chính mà tôi không nghĩ là hữu ích khi coi ECS thuộc về một lớp OOP là vì hầu hết các thực hành SE liên quan đến OOP xoay quanh sự ổn định của giao diện công cộng, với các chức năng mô hình hóa giao diện công cộng , không phải dữ liệu. Ý tưởng cơ bản là phần lớn các phụ thuộc công cộng chảy vào các hàm trừu tượng, chứ không phải dữ liệu cụ thể. Và do đó, OOP có xu hướng rất tốn kém khi thay đổi các hành vi thiết kế cơ bản, trong khi làm cho nó rất rẻ để thay đổi các chi tiết cụ thể (như dữ liệu và mã cần thiết để thực hiện chức năng).

ECS hoàn toàn khác nhau về vấn đề này khi xem xét mọi thứ được kết hợp như thế nào khi phần lớn các phụ thuộc công cộng chảy vào dữ liệu cụ thể: từ hệ thống đến các thành phần. Do đó, mọi thực hành SE liên quan đến ECS sẽ xoay quanh tính ổn định của dữ liệu , bởi vì các giao diện (thành phần) được sử dụng rộng rãi và công khai nhất thực sự chỉ là dữ liệu.

Do đó, ECS giúp dễ dàng thực hiện những việc như thay thế công cụ kết xuất OpenGL cho DirectX, ngay cả khi cả hai được triển khai với chức năng hoàn toàn khác nhau và không chia sẻ cùng một thiết kế, cung cấp cả công cụ DX và GL có quyền truy cập vào cùng một dữ liệu ổn định. Trong khi đó, nó sẽ rất tốn kém và đòi hỏi phải viết lại một loạt các hệ thống để thay đổi, giả sử, biểu diễn dữ liệu của a MotionComponent.

Điều đó trái ngược với những gì chúng ta thường liên kết với OOP, ít nhất là về đặc điểm khớp nối và những gì cấu thành "giao diện công cộng" so với "chi tiết triển khai riêng tư". Tất nhiên trong cả hai trường hợp, "chi tiết triển khai" đều dễ thay đổi, nhưng trong ECS, đó là thiết kế dữ liệu tốn kém để thay đổi (dữ liệu không phải là chi tiết triển khai trong ECS) và trong OOP, đó là thiết kế chức năng tốn kém để thay đổi (thiết kế các chức năng không phải là một chi tiết triển khai trong OOP). Vì vậy, đó là một ý tưởng rất khác về "chi tiết triển khai" và một trong những điều hấp dẫn tôi đối với một ECS từ góc độ bảo trì là trong miền của tôi, dữ liệu cần thiết để thực hiện mọi thứ dễ dàng ổn định hơn và thiết kế chính xác một lần và cho tất cả trả trước hơn tất cả những điều khác nhau chúng ta có thể làm với dữ liệu đó (sẽ thay đổi mọi lúc khi khách hàng thay đổi ý định và đề xuất người dùng mới tràn vào). Kết quả là, tôi thấy chi phí bảo trì giảm mạnh khi chúng tôi bắt đầu chuyển các phụ thuộc ra khỏi các hàm trừu tượng đối với dữ liệu trung tâm thô (nhưng vẫn quan tâm đến việc hệ thống nào truy cập vào thành phần nào để cho phép duy trì bất biến ở mức độ bất chấp tất cả các dữ liệu về mặt khái niệm truy cập toàn cầu).

Và trong trường hợp của tôi ít nhất, SDK ECS với API và tất cả các thành phần thực sự được triển khai trong C và không giống với OOP. Tôi đã tìm thấy C quá đủ cho mục đích như vậy do thiếu OO vốn có trong các kiến ​​trúc ECS và mong muốn có một kiến ​​trúc plugin có thể được sử dụng bởi phạm vi ngôn ngữ và trình biên dịch rộng nhất. Các hệ thống vẫn được triển khai trong C ++ vì C ++ làm cho mọi thứ rất thuận tiện và các hệ thống mô hình hóa phần lớn sự phức tạp và ở đó tôi thấy sử dụng cho rất nhiều thứ có thể được coi là gần với OOP hơn, nhưng đó là chi tiết triển khai. Bản thân thiết kế kiến ​​trúc vẫn giống C.

Vì vậy, tôi nghĩ rằng hơi khó hiểu, ít nhất, để cố gắng nói một ECS là OO theo định nghĩa. Ít nhất thì các nguyên tắc cơ bản làm những việc hoàn toàn xoay 180 độ so với nhiều nguyên tắc cơ bản thường liên quan đến OOP, bắt đầu bằng việc đóng gói và có thể kết thúc bằng những đặc điểm được coi là mong muốn.

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.