Cập nhật (tóm tắt)
Vì tôi đã viết một câu trả lời khá dài dòng, đây là tất cả những gì nó rút ra:
- Không gian tên là tốt, sử dụng chúng bất cứ khi nào nó có ý nghĩa
- Việc sử dụng
inGameIO
và playerIO
các lớp có thể sẽ cấu thành vi phạm SRP. Điều đó có nghĩa là bạn đang ghép nối cách bạn xử lý IO với logic ứng dụng.
- Có một vài lớp IO chung, được sử dụng (hoặc đôi khi được chia sẻ) bởi các lớp xử lý. Các lớp xử lý này sau đó sẽ dịch đầu vào thô thành định dạng mà logic ứng dụng của bạn có thể hiểu được.
- Tương tự với đầu ra: điều này có thể được thực hiện bởi các lớp khá chung chung, nhưng chuyển trạng thái trò chơi thông qua một đối tượng xử lý / ánh xạ dịch trạng thái trò chơi nội bộ thành thứ mà các lớp IO chung có thể xử lý.
Tôi nghĩ rằng bạn đang nhìn điều này sai cách. Bạn đang tách IO theo chức năng của các thành phần của ứng dụng, trong khi đó - với tôi - sẽ có ý nghĩa hơn khi có các lớp IO riêng biệt dựa trên nguồn và "loại" IO.
Có một số KeyboardIO
lớp cơ sở / chung chung MouseIO
để bắt đầu, và sau đó dựa trên thời điểm và nơi bạn cần chúng, có các lớp con xử lý IO khác nhau.
Ví dụ: nhập văn bản là thứ bạn có thể muốn xử lý khác với điều khiển trong trò chơi. Bạn sẽ thấy mình muốn ánh xạ các khóa nhất định khác nhau tùy theo từng trường hợp sử dụng, nhưng ánh xạ đó không phải là một phần của chính IO, đó là cách bạn xử lý IO.
Bám sát SRP, tôi có một vài lớp mà tôi có thể sử dụng cho IO bàn phím. Tùy thuộc vào tình huống, có lẽ tôi sẽ muốn tương tác với các lớp này một cách khác nhau, nhưng công việc duy nhất của họ là cho tôi biết người dùng đang làm gì.
Sau đó, tôi sẽ đưa các đối tượng này vào một đối tượng xử lý để ánh xạ IO thô vào thứ gì đó mà logic ứng dụng của tôi có thể hoạt động (ví dụ: người dùng nhấn "w" , trình xử lý ánh xạ lên MOVE_FORWARD
).
Những trình xử lý này lần lượt được sử dụng để làm cho các nhân vật di chuyển và vẽ màn hình tương ứng. Một sự đơn giản hóa quá mức, nhưng ý chính của nó là loại cấu trúc này:
[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
||
==> [ Controls.Keyboard.InGameMapper ]
[ Game.Engine ] <- Controls.Keyboard.InGameMapper
<- IO.Screen
<- ... all sorts of stuff here
InGameMapper.move() //returns MOVE_FORWARD or something
||
==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
3. IO.Screen.draw();//generate actual output
Những gì chúng ta có bây giờ là một lớp chịu trách nhiệm cho IO bàn phím ở dạng thô. Một lớp khác dịch dữ liệu này thành thứ gì đó mà công cụ trò chơi thực sự có thể hiểu được, dữ liệu này sau đó được sử dụng để cập nhật trạng thái của tất cả các thành phần liên quan, và cuối cùng, một lớp riêng sẽ đảm nhiệm việc xuất ra màn hình.
Mỗi một lớp có một công việc duy nhất: xử lý đầu vào bàn phím được thực hiện bởi một lớp không biết / quan tâm / phải biết đầu vào mà nó xử lý nghĩa là gì. Tất cả những gì nó làm là biết làm thế nào để có được đầu vào (được đệm, không có bộ đệm, ...).
Trình xử lý dịch điều này thành một đại diện nội bộ cho phần còn lại của ứng dụng để hiểu ý nghĩa của thông tin này.
Công cụ trò chơi lấy dữ liệu đã được dịch và sử dụng nó để thông báo cho tất cả các thành phần có liên quan rằng có gì đó đang diễn ra. Mỗi thành phần này chỉ làm một việc, cho dù đó là kiểm tra va chạm hay thay đổi hoạt hình nhân vật, điều đó không thành vấn đề, điều đó tùy thuộc vào từng đối tượng riêng lẻ.
Các đối tượng này sau đó chuyển tiếp trạng thái của chúng trở lại và dữ liệu này được truyền tới Game.Screen
, về bản chất là một trình xử lý IO nghịch đảo. Nó ánh xạ biểu diễn bên trong vào một cái gì đó mà IO.Screen
thành phần có thể sử dụng để tạo đầu ra thực tế.