Tôi sẽ bắt đầu bằng cách không nghĩ về một người quản lý tài sản . Suy nghĩ về kiến trúc của bạn theo các thuật ngữ được xác định một cách lỏng lẻo (như "người quản lý") có xu hướng cho phép bạn quét sạch nhiều chi tiết dưới tấm thảm, và do đó, việc giải quyết một giải pháp trở nên khó khăn hơn.
Tập trung vào các nhu cầu cụ thể của bạn, điều này dường như sẽ làm với việc tạo ra một cơ chế tải tài nguyên trừu tượng hóa bộ lưu trữ gốc bên dưới và cho phép mở rộng bộ loại được hỗ trợ. Chẳng có gì thực sự trong câu hỏi của bạn liên quan đến, ví dụ, bộ nhớ đệm của các tài nguyên đã được tải - điều này tốt, bởi vì theo nguyên tắc trách nhiệm duy nhất, có lẽ bạn nên xây dựng bộ đệm tài sản như một thực thể riêng biệt và tổng hợp hai giao diện ở nơi khác , khi thích hợp.
Để giải quyết mối quan tâm cụ thể của bạn, bạn nên thiết kế trình tải của mình để nó không tự tải bất kỳ tài sản nào, mà thay vào đó ủy thác trách nhiệm cho các giao diện được điều chỉnh để tải các loại tài sản cụ thể. Ví dụ:
interface ITypeLoader {
object Load (Stream assetStream);
}
Bạn có thể tạo các lớp mới thực hiện giao diện này, với mỗi lớp mới được tùy chỉnh để tải một loại dữ liệu cụ thể từ một luồng. Bằng cách sử dụng một luồng, trình tải loại có thể được viết dựa trên giao diện phổ biến, không lưu trữ và không phải mã hóa cứng để tải từ đĩa hoặc cơ sở dữ liệu; điều này thậm chí sẽ cho phép bạn tải tài sản của mình từ các luồng mạng (có thể rất hữu ích trong việc triển khai tải lại tài sản khi trò chơi của bạn đang chạy trên bảng điều khiển và các công cụ chỉnh sửa của bạn trên PC được kết nối mạng).
Trình tải tài sản chính của bạn cần có khả năng đăng ký và theo dõi các trình tải cụ thể loại này:
class AssetLoader {
public void RegisterType (string key, ITypeLoader loader) {
loaders[key] = loader;
}
Dictionary<string, ITypeLoader> loaders = new Dictionary<string, ITypeLoader>();
}
"Khóa" được sử dụng ở đây có thể là bất cứ thứ gì bạn thích - và nó không cần phải là một chuỗi, nhưng chúng không dễ bắt đầu. Chìa khóa sẽ quyết định đến cách bạn mong muốn người dùng xác định một tài sản cụ thể và sẽ được sử dụng để tra cứu trình tải phù hợp. Vì bạn muốn che giấu sự thật rằng việc triển khai có thể đang sử dụng một hệ thống tệp hoặc cơ sở dữ liệu, bạn không thể có người dùng tham chiếu đến các tài sản theo đường dẫn hệ thống tệp hoặc bất cứ thứ gì tương tự.
Người dùng nên tham khảo một tài sản với thông tin tối thiểu. Trong một số trường hợp, chỉ một tên tệp là đủ, nhưng tôi thấy rằng thường sử dụng một cặp loại / tên nên mọi thứ đều rất rõ ràng. Do đó, người dùng có thể tham khảo một thể hiện được đặt tên của một trong các tệp XML hoạt hình của bạn là "AnimationXml","PlayerWalkCycle"
.
Ở đây, AnimationXml
sẽ là chìa khóa mà bạn đã đăng ký AnimationXmlLoader
, thực hiện IAssetLoader
. Rõ ràng, PlayerWalkCycle
xác định tài sản cụ thể. Đặt tên loại và tên tài nguyên, trình tải tài sản của bạn có thể truy vấn bộ lưu trữ liên tục của nó để tìm các byte thô của tài sản đó. Vì chúng tôi sẽ có tính tổng quát tối đa ở đây, bạn có thể thực hiện điều này bằng cách chuyển cho trình tải một phương tiện truy cập lưu trữ khi bạn tạo nó, cho phép bạn thay thế phương tiện lưu trữ bằng bất kỳ thứ gì có thể cung cấp luồng sau này:
interface IAssetStreamProvider {
Stream GetStream (string type, string name);
}
class AssetLoader {
public AssetLoader (IAssetStreamProvider streamProvider) {
provider = streamProvider;
}
object LoadAsset (string type, string name) {
var loader = loaders[type];
var stream = provider.GetStream(type, name);
return loader.Load(stream);
}
public void RegisterType (string type, ITypeLoader loader) {
loaders[type] = loader;
}
IAssetStreamProvider provider;
Dictionary<string, ITypeLoader> loaders = new Dictionary<string, ITypeLoader>();
}
Một nhà cung cấp luồng rất đơn giản sẽ chỉ cần tìm trong một thư mục gốc tài sản được chỉ định cho một thư mục con có tên type
và tải các byte thô của tệp có tên name
vào một luồng và trả về nó.
Nói tóm lại, những gì bạn có ở đây là một hệ thống trong đó:
- Có một lớp biết cách đọc byte thô từ một loại lưu trữ phụ trợ (đĩa, cơ sở dữ liệu, luồng mạng, bất cứ điều gì).
- Có các lớp biết cách biến một luồng byte thô thành một loại tài nguyên cụ thể và trả về nó.
- "Trình tải tài sản" thực tế của bạn chỉ có một tập hợp các aboves trên và biết cách đưa đầu ra của nhà cung cấp luồng vào trình tải cụ thể theo loại và do đó tạo ra một tài sản cụ thể. Bằng cách đưa ra các cách để định cấu hình nhà cung cấp luồng và trình tải cụ thể theo loại, bạn có một hệ thống có thể được mở rộng bởi khách hàng (hoặc chính bạn) mà không phải sửa đổi mã trình tải tài sản thực tế.
Một số cảnh báo và ghi chú cuối cùng:
Đoạn mã trên về cơ bản là C #, nhưng nên dịch sang bất kỳ ngôn ngữ nào với nỗ lực tối thiểu. Để tạo điều kiện cho điều này, tôi đã bỏ qua rất nhiều thứ như kiểm tra lỗi hoặc sử dụng đúng cách IDisposable
và các thành ngữ khác có thể không áp dụng trực tiếp trong các ngôn ngữ khác. Những người còn lại là bài tập về nhà cho người đọc.
Tương tự, tôi trả lại tài sản cụ thể như object
trên, nhưng bạn có thể sử dụng chung hoặc mẫu hoặc bất cứ thứ gì để tạo ra một loại đối tượng cụ thể hơn nếu bạn muốn (bạn nên làm việc với nó).
Như trên, tôi không đối phó với bộ nhớ đệm ở đây. Tuy nhiên, bạn có thể thêm bộ nhớ đệm dễ dàng và với cùng loại tổng quát và cấu hình. Hãy thử nó và xem!
Có rất nhiều và rất nhiều cách để làm điều này, và chắc chắn không có cách nào hay sự đồng thuận, đó là lý do tại sao bạn không thể tìm thấy một cách. Tôi đã cố gắng cung cấp đủ mã để có được các điểm cụ thể mà không biến câu trả lời này thành một đoạn mã dài. Nó đã quá dài như nó là. Nếu bạn có câu hỏi làm rõ, hãy bình luận hoặc tìm tôi trong cuộc trò chuyện .