Tôi đã gặp một vấn đề trong trò chơi mà tôi đang thực hiện trong C#. Đó là một trò chơi kết hợp dựa trên gạch đơn giản và vấn đề nảy sinh khi tôi cố gắng tạo ra:Sử dụng GetType/instanceof trong C# so với các lựa chọn thay thế
Giả sử chúng ta có các loại gạch cơ bản, hình vuông và hình thoi, tất cả đều là lớp con của Ngói. Thay vì có vòng tròn chỉ phù hợp với vòng kết nối, tôi đã cố gắng trích xuất hành vi "đối sánh" thành phương thức Gạch trừu tượng: canMatchWith (Ngói t). Gạch cũng có hai phương pháp để thêm/loại bỏ Gạch mà chúng có thể khớp với.
Vì vậy, hãy nói rằng chúng tôi có một hình tròn ở giữa trò chơi của chúng tôi và chúng tôi có một powerup có nội dung "Gạch tròn có thể khớp với ô vuông lần lượt này". Tôi sẽ đi qua tất cả các gạch Circle và nói circleTile.addCanMatchWith (typeof (Square)). Bên trong, chúng ta có một List canMatchWith.
Sau đó, tôi muốn nói "Vòng kết nối không còn có thể khớp với hình vuông" và chỉ cần nói circleTile.removeCanMatchWith (typeOf (Square)).
Đây là giải pháp hiện tại của tôi và nó hoạt động tuyệt vời không có hiệu suất mà tôi đã nhận thấy (Đó là trò chơi xếp hình dựa trên gạch, vì vậy các loại này chỉ được đánh giá một lần cho mỗi lần di chuyển, chứ không phải khung theo khung). Tuy nhiên, giọng nói trong đầu tôi đang nói với tôi rằng đây là một cách tồi tệ để hoàn thành hành vi này. Vì vậy, tôi có một số lựa chọn thay thế:
- Enums ... Mỗi ô có thể được tạo với một biến kiểu Tiletype. Điều này sẽ được khởi tạo trong hàm tạo và đặt thành Type.SQUARE cho các ô vuông, v.v. Sau đó, mỗi Tile sẽ có một List canMatchWith, và chức năng giống như việc thực hiện ban đầu của tôi. Ngoại trừ trong trường hợp này, nó phức tạp hơn một chút. Nói rằng tôi có một số lớp con vòng tròn, hình bầu dục và hình elip. Tôi muốn hình bầu dục để có thể phù hợp với hình vuông chỉ, nhưng elipses có thể phù hợp với tất cả các vòng tròn và không vuông.
Vấn đề ở đây là dự phòng, enum của tôi bây giờ sẽ có OVAL và ELIPSE, và lớp Elipse sẽ có (CIRCLE, OVAL, ELIPSE TileTypes) là loại có thể khớp với. Điều này là hoàn toàn dư thừa, tôi muốn chỉ nói "Circle" mà tôi có thể với các loại. Tôi cho rằng các Brick có thể có TileType baseType và TileType actualType.
- Một số dạng thành phần hành vi. Hãy quên đi các lớp con Tile, chỉ cần đưa ra các phương thức Tiles và một biến cá thể cho List. Sau đó, tại thời gian chạy, chúng tôi chỉ có thể nói someTile.addCanMatch (mới CircleMatchBehavior()). Điều này có vẻ ngớ ngẩn, như tôi sẽ có một loạt các lớp học chỉ nói rằng bạn có thể phù hợp với một hình dạng cụ thể.
Tóm lại, những gì tôi đang cố gắng thực hiện là có nhiều loại đối tượng có thể tương tác với bất kỳ số loại nào khác nhau. Câu hỏi đặt ra là, tôi nên sử dụng cái gì cho Loại. Có sử dụng GetType ở đây không? Enums? Hoặc là có một chiến lược tốt hơn ai đó sẽ giới thiệu? Tôi đang cố gắng hết sức có thể, những viên gạch này không nên có bất kỳ phụ thuộc mã hóa nào trên các loại gạch khác, và phải có khả năng thay đổi những người mà chúng có thể tương tác khi đang bay. Giả sử tôi tạo một lớp con Tile mới, ngũ giác ... tốt, Pentagons có thể phù hợp với Squares, Circles và Pentagons. Dễ dàng với việc thực hiện của tôi, nhưng một cái gì đó nói với tôi đây là một thực hành OOP bẩn.
Tôi cảm thấy mình phải sử dụng các loại/Enums vì tôi không cố gắng nói thisTile.addCanMatch (Tile someOtherObject). Đó là quá cụ thể, tôi muốn thisTile để có thể phù hợp với tất cả các gạch là trường hợp của một lớp học cụ thể.
Tôi sợ rằng tôi không phải là một nhà thiết kế có tay nghề đủ để đề xuất một thiết kế hoàn chỉnh cho bạn, nhưng nếu không có thực tế * khác biệt * chức năng trong cách Circles và Các hoạt động của Ovals có thể tốt hơn nếu có tất cả các cá thể là lớp 'Tile' và sau đó thiết lập một số thuộc tính' Behavior'. Tất cả các vòng tròn trên bảng có thể chia sẻ cùng một đối tượng 'Hành vi', và sau đó khi các quy tắc thay đổi cho một lượt, bạn có thể đặt các thay đổi trên đối tượng' Hành vi' đó. Điều này có thể dẫn đến sao chép mã ít hơn, nếu tôi hiểu được tình huống. – Katana314
Nếu tôi hiểu chính xác bạn, điều này giống như Thành phần hành vi # 2 của tôi. Nỗi sợ hãi của tôi ở đây là hành vi nổ. Ví dụ, MatchesWithCirclesAndSquaresBehavior. Xem những gì tôi đang nhận được? Nếu có 5 loại gạch, thì chúng ta có 5 chọn 1 cộng 5 chọn 2 cộng 5 chọn 3 cộng 5 chọn 4 cộng 5 chọn 5 tổ hợp hành vi. Điều này có vẻ còn tồi tệ hơn GetType. Tuy nhiên, tôi có thể hiểu nhầm điều gì đó trong đề xuất của bạn. Các gạch tự làm bất cứ điều gì họ muốn, người ta có thể làm một hình ảnh động vụ nổ, vv Điều này chỉ cho nếu gạch có thể phù hợp với nhau. – user2045279
Tôi đã không đề xuất Hành vi là một Enum hoặc một lớp không thể sửa đổi. Bạn có thể phân lớp nó theo cách, nhưng chủ yếu tôi chỉ mong đợi nó có một bộ sưu tập nội bộ đại diện cho loại đó là (Circle) và loại (s) mà nó có thể phù hợp với (Square). Sau đó, bạn có thể thay đổi điều đó theo cách có phần dữ liệu. Tôi chắc chắn đồng ý rằng bất cứ điều gì sẽ dẫn đến khối lượng lớn nếu/else/switch nên tránh để ủng hộ việc thiết lập đối tượng tốt, nhưng chúng tôi cũng muốn tránh viết một lớp mới để giải thích một số biến thể không mới. – Katana314