BobDalgleish đã lưu ý rằng mẫu (chống) này được gọi là " dữ liệu tramp ".
Theo kinh nghiệm của tôi, nguyên nhân phổ biến nhất của dữ liệu tramp quá mức là có một loạt các biến trạng thái được liên kết nên thực sự được gói gọn trong một đối tượng hoặc cấu trúc dữ liệu. Đôi khi, thậm chí có thể cần phải lồng một loạt các đối tượng để tổ chức dữ liệu đúng cách.
Ví dụ đơn giản, hãy xem xét một trò chơi có nhân vật người chơi có thể tùy chỉnh, với các thuộc tính như playerName
, playerEyeColor
v.v. Tất nhiên, người chơi cũng có một vị trí vật lý trên bản đồ trò chơi và nhiều thuộc tính khác như, mức độ sức khỏe hiện tại và tối đa, v.v.
Trong lần lặp đầu tiên của một trò chơi như vậy, có thể là một lựa chọn hoàn toàn hợp lý để biến tất cả các thuộc tính này thành các biến toàn cục - sau tất cả, chỉ có một người chơi và hầu hết mọi thứ trong trò chơi đều liên quan đến người chơi. Vì vậy, trạng thái toàn cầu của bạn có thể chứa các biến như:
playerName = "Bob"
playerEyeColor = GREEN
playerXPosition = -8
playerYPosition = 136
playerHealth = 100
playerMaxHealth = 100
Nhưng tại một số điểm, bạn có thể thấy rằng bạn cần thay đổi thiết kế này, có lẽ vì bạn muốn thêm chế độ nhiều người chơi vào trò chơi. Lần thử đầu tiên, bạn có thể thử biến tất cả các biến đó thành cục bộ và chuyển chúng đến các hàm cần chúng. Tuy nhiên, sau đó bạn có thể thấy rằng một hành động cụ thể trong trò chơi của bạn có thể liên quan đến chuỗi cuộc gọi chức năng như, nói:
mainGameLoop()
-> processInputEvent()
-> doPlayerAction()
-> movePlayer()
-> checkCollision()
-> interactWithNPC()
-> interactWithShopkeeper()
... và interactWithShopkeeper()
chức năng này có người bán hàng gọi địa chỉ của người chơi theo tên, vì vậy bây giờ bạn đột nhiên cần truyền playerName
dữ liệu dưới dạng thông qua tất cả các chức năng đó. Và, tất nhiên, nếu chủ cửa hàng nghĩ rằng những người chơi mắt xanh là ngây thơ, và sẽ tính giá cao hơn cho họ, thì bạn cần phải playerEyeColor
thông qua toàn bộ chuỗi chức năng, v.v.
Tất nhiên , giải pháp thích hợp là xác định một đối tượng người chơi gói gọn tên, màu mắt, vị trí, sức khỏe và bất kỳ thuộc tính nào khác của nhân vật người chơi. Bằng cách đó, bạn chỉ cần chuyển đối tượng duy nhất đó cho tất cả các chức năng liên quan đến người chơi.
Ngoài ra, một số chức năng trên có thể được tạo tự nhiên thành các phương thức của đối tượng người chơi đó, nó sẽ tự động cấp cho họ quyền truy cập vào các thuộc tính của người chơi. Theo một cách nào đó, đây chỉ là đường cú pháp, vì việc gọi một phương thức trên một đối tượng có hiệu quả vượt qua thể hiện đối tượng như một tham số ẩn cho phương thức, nhưng nó làm cho mã trông rõ ràng và tự nhiên hơn nếu được sử dụng đúng cách.
Tất nhiên, một trò chơi thông thường sẽ có trạng thái "toàn cầu" hơn nhiều so với chỉ người chơi; ví dụ: bạn gần như chắc chắn có một loại bản đồ mà trò chơi diễn ra và một danh sách các nhân vật không phải người chơi di chuyển trên bản đồ, và có thể các vật phẩm được đặt trên đó, v.v. Bạn cũng có thể vượt qua tất cả những người xung quanh dưới dạng các đối tượng lang thang, nhưng điều đó sẽ lại làm lộn xộn các đối số phương thức của bạn.
Thay vào đó, giải pháp là để các đối tượng lưu trữ các tham chiếu đến bất kỳ đối tượng nào khác mà chúng có mối quan hệ vĩnh viễn hoặc tạm thời. Vì vậy, ví dụ, đối tượng người chơi (và có thể là bất kỳ đối tượng NPC nào) có lẽ nên lưu trữ một tham chiếu đến đối tượng "thế giới trò chơi", có tham chiếu đến cấp độ / bản đồ hiện tại, do đó, một phương thức như player.moveTo(x, y)
không cần phải được cung cấp rõ ràng bản đồ như là một tham số.
Tương tự, nếu nhân vật người chơi của chúng ta có một con chó cưng đi theo họ xung quanh, chúng ta sẽ tự nhiên nhóm tất cả các biến trạng thái mô tả con chó thành một đối tượng và cung cấp cho đối tượng người chơi một tham chiếu đến con chó (để người chơi có thể , nói, gọi con chó theo tên) và ngược lại (để con chó biết người chơi đang ở đâu). Và, tất nhiên, có lẽ chúng ta muốn làm cho người chơi và các đối tượng chó cả hai lớp con của một đối tượng "diễn viên" chung chung hơn, để chúng ta có thể sử dụng lại cùng một mã cho, di chuyển cả hai trên bản đồ.
Thi thiên Mặc dù tôi đã sử dụng một trò chơi làm ví dụ, có những loại chương trình khác cũng xuất hiện những vấn đề như vậy. Tuy nhiên, theo kinh nghiệm của tôi, vấn đề tiềm ẩn có xu hướng luôn giống nhau: bạn có một loạt các biến riêng biệt (dù là cục bộ hay toàn cầu) thực sự muốn được gộp lại thành một hoặc nhiều đối tượng liên kết với nhau. Cho dù "dữ liệu tramp" xâm nhập vào các chức năng của bạn bao gồm các cài đặt tùy chọn "toàn cầu" hoặc truy vấn cơ sở dữ liệu được lưu trong bộ nhớ cache hoặc vectơ trạng thái trong một mô phỏng số, thì giải pháp luôn luôn xác định bối cảnh tự nhiên mà dữ liệu thuộc về và biến nó thành một đối tượng (hoặc bất cứ điều gì tương đương gần nhất trong ngôn ngữ bạn đã chọn).