Bir varlık yöneticisi düşünmeyerek başlardım . Mimarinizi gevşek tanımlanmış terimlerle ("yönetici" gibi) düşünmek, halının altında birçok ayrıntıyı zihinsel olarak süpürmenize izin verir ve sonuç olarak bir çözüme yerleşmek daha zor hale gelir.
Temel kaynak deposunu soyutlayan ve desteklenen tür kümesinin genişletilebilirliğine izin veren bir kaynak yükleme mekanizması oluşturmakla ilgili görünen özel gereksinimlerinize odaklanın. Örneğin, önceden yüklenmiş kaynakların önbelleğe alınmasıyla ilgili gerçekten hiçbir şey yok - bu iyi, çünkü tek sorumluluk ilkesine uygun olarak muhtemelen bir varlık önbelleği ayrı bir varlık olarak oluşturmalı ve iki arayüzü başka bir yerde toplamalısınız , uygun.
Özel endişenizi gidermek için yükleyicinizi herhangi bir varlığın yüklenmesini değil, belirli varlık türlerini yüklemeye uyarlanmış arayüzlere karşı sorumluluğu devredecek şekilde tasarlamalısınız. Örneğin:
interface ITypeLoader {
object Load (Stream assetStream);
}
Bu arabirimi uygulayan yeni sınıflar oluşturabilirsiniz; her yeni sınıf bir akıştan belirli bir veri türünü yüklemek üzere uyarlanmıştır. Bir akış kullanarak, tip yükleyici, depolamadan bağımsız ortak bir arabirime karşı yazılabilir ve diskten veya veritabanından yüklenmek için sabit kodlanması gerekmez; bu bile varlıklarınızı ağ akışlarından yüklemenize izin verir (bu, oyununuz bir konsolda çalışırken ve varlıkların ağa bağlı bir PC'de düzenleme araçlarınız çalışırken varlıkların sıcak olarak yeniden yüklenmesini uygulamada çok yararlı olabilir).
Ana varlık yükleyicinizin bu türe özgü yükleyicileri kaydedebilmesi ve izleyebilmesi gerekir:
class AssetLoader {
public void RegisterType (string key, ITypeLoader loader) {
loaders[key] = loader;
}
Dictionary<string, ITypeLoader> loaders = new Dictionary<string, ITypeLoader>();
}
Burada kullanılan "anahtar" istediğiniz gibi olabilir - ve bir dize olması gerekmez, ancak bunlarla başlamak kolaydır. Anahtar, bir kullanıcının belirli bir varlığı nasıl tanımlamasını beklediğinize bağlı olacaktır ve uygun yükleyiciyi aramak için kullanılacaktır. Uygulamanın bir dosya sistemi veya veritabanı kullanıyor olabileceği gerçeğini gizlemek istediğiniz için, kullanıcılarınızın dosya sistemi yolu veya benzeri bir şeyle varlıklara atıfta bulunmasını sağlayamazsınız.
Kullanıcılar, asgari düzeyde bilgiye sahip bir varlığa başvurmalıdır. Bazı durumlarda, yalnızca bir dosya adı tek başına yeterli olur, ancak her şeyin çok açık olması için bir tür / ad çifti kullanmanın genellikle arzu edilir olduğunu gördüm. Bu nedenle, bir kullanıcı animasyon XML dosyalarınızdan birinin adlandırılmış bir örneğini olarak belirtebilir "AnimationXml","PlayerWalkCycle"
.
Burada, AnimationXml
altında kaydolduğunuz AnimationXmlLoader
ve uyguladığınız anahtar olacaktır IAssetLoader
. Açıkçası, PlayerWalkCycle
belirli bir varlığı tanımlar. Bir tür adı ve kaynak adı verildiğinde, varlık yükleyiciniz kalıcı depolama alanını söz konusu varlığın ham baytları için sorgulayabilir. Burada maksimum genelliğe gideceğimizden, bunu yükleyiciyi oluştururken bir depolama erişimi aracı geçirerek uygulayabilir ve depolama ortamını daha sonra bir akış sağlayabilecek herhangi bir şeyle değiştirmenize izin verir:
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>();
}
Çok basit bir akış sağlayıcısı, belirtilen bir varlık kök dizininde adlandırılmış bir alt dizini arar ve adlandırılan type
dosyanın ham baytlarını name
bir akışa yükler ve döndürür.
Kısacası, burada sahip olduğunuz bir sistem:
- Bir çeşit arka uç deposundan (disk, veritabanı, ağ akışı, her neyse) ham baytların nasıl okunacağını bilen bir sınıf var.
- Ham bayt akışını belirli bir kaynağa dönüştürmeyi ve geri döndürmeyi bilen sınıflar vardır.
- Gerçek "varlık yükleyiciniz" sadece yukarıda belirtilenlerin bir koleksiyonuna sahiptir ve akış sağlayıcısının çıktısının türe özgü yükleyiciye nasıl bağlanacağını ve böylece somut bir varlığın nasıl üretileceğini bilir. Akış sağlayıcısını ve türe özgü yükleyicileri yapılandırmanın yollarını açığa çıkararak, gerçek varlık yükleyici kodunu değiştirmek zorunda kalmadan istemciler (veya kendiniz) tarafından genişletilebilen bir sisteminiz olur.
Bazı uyarılar ve son notlar:
Yukarıdaki kod temel olarak C # 'dır, ancak minimum çaba ile hemen hemen her dile tercüme edilmelidir. Bunu kolaylaştırmak için, hata denetimi veya doğru kullanımı IDisposable
ve doğrudan diğer dillerde uygulanamayan diğer deyimler gibi birçok şeyi atladım. Bunlar okuyucuya ödev olarak bırakılıyor.
Benzer şekilde, somut varlığı object
yukarıdaki gibi döndürdüm , ancak isterseniz daha spesifik bir nesne türü üretmek için jenerikler veya şablonlar veya her şeyi kullanabilirsiniz (çalışmanız iyi olur).
Yukarıdaki gibi, burada önbellekleme ile hiç ilgilenmiyorum. Ancak, önbelleklemeyi kolayca ve aynı genelliğe ve yapılandırılabilirliğe ekleyebilirsiniz. Deneyin ve görün!
Bunu yapmak için çok ve çok ve birçok yol var ve kesinlikle tek bir yol ya da fikir birliği yok, bu yüzden bir tane bulamadınız. Ben ağrılı bir uzun kod duvar bu cevap dönmeden genelinde belirli noktaları almak için yeterli kod sağlamaya çalıştım. Oldukça fazla uzun. Açıklayıcı sorularınız varsa, yorum yapmaktan veya beni sohbette bulmaktan çekinmeyin .