Bu gerçekten çok önemli bir soru ve hemen hemen her uygulamanın temel bir parçası olmasına rağmen yeterince önem verilmediği için yanlış yapılıyor. İşte yönergelerim:
Tüm ayarları içeren yapılandırma sınıfınız yalnızca düz bir eski veri türü, struct / class olmalıdır:
class Config {
int prop1;
float prop2;
SubConfig subConfig;
}
Yöntemlere sahip olmamalı ve miras içermemelidir (bir değişken alanı uygulamak için dilinizde sahip olduğunuz tek seçenek olmadığı sürece - bir sonraki paragrafa bakın). Ayarları daha küçük özel yapılandırma sınıflarına gruplamak için kompozisyon kullanabilir ve kullanmalıdır (örn. Yukarıdaki subConfig). Bu şekilde yaparsanız, birim testlerde ve genel olarak uygulamada en az bağımlılığa sahip olacağı için etrafta dolaşmak ideal olacaktır.
Farklı kurulumlar için yapıların heterojen olması durumunda, büyük olasılıkla değişken türleri kullanmanız gerekecektir. Değeri sağ (alt) yapılandırma sınıfına yayınlamak için değeri okuduğunuzda bir noktada dinamik bir döküm eklemeniz gerektiği kabul edilir ve şüphesiz bu başka bir yapılandırma ayarına bağlı olacaktır.
Bunu yaparak tüm ayarları alanlar olarak yazmak konusunda tembel olmamalısınız:
class Config {
Dictionary<string, string> values;
};
Bu, hangi alanlarla uğraştığını bilmek zorunda olmayan genelleştirilmiş bir serileştirme sınıfı yazabileceğiniz anlamına geldiği için caziptir, ancak yanlıştır ve nedenini bir anda açıklayacağım.
Konfigürasyonun seri hale getirilmesi tamamen ayrı bir sınıfta yapılır. Bunu yapmak için hangi API'yi veya kütüphaneyi kullanırsanız kullanın, serileştirme işlevinizin gövdesi temel olarak dosyadaki yol / anahtardan nesnenin üzerindeki alana eşleme anlamına gelen girişler içermelidir. Bazı diller iyi bir içgözlem sağlar ve bunu sizin için kutudan çıkarır, diğerleri ise eşlemeyi açıkça yazmanız gerekir, ancak asıl önemli olan eşleştirmeyi yalnızca bir kez yazmanız gerekir. Örneğin c ++ boost program seçenekleri ayrıştırıcı belgelerinden uyarlanmış bu özü düşünün:
struct Config {
int opt;
} conf;
po::options_description desc("Allowed options");
desc.add_options()
("optimization", po::value<int>(&conf.opt)->default_value(10);
Son satırın temelde "optimizasyon" ifadesinin Config :: opt ile eşleştiğini ve ayrıca beklediğiniz türde bir bildirim olduğunu unutmayın. Tür beklediğiniz gibi değilse, dosyadaki parametre gerçekten bir kayan nokta veya int değilse veya yoksa yapılandırma okumasının başarısız olmasını istersiniz. Ie Dosyayı okuduğunuzda hata oluşmalıdır, çünkü sorun dosyanın formatı / doğrulamasıyla ilgilidir ve bir dış / dönüş kodu atmanız ve tam sorunu bildirmeniz gerekir. Bunu programda daha sonraya ertelememelisiniz. Bu nedenle, dosya okunurken başarısız olmayacak - değer gerekli olana kadar döküm ertelendiğinden, yukarıda belirtildiği gibi tüm Sözlük stili Conf'yi yakalamaya cazip olmamalısınız.
Config sınıfını bazı şekillerde salt okunur yapmalısınız - sınıfın içeriğini oluştururken ve dosyadan başlatırken bir kez ayarlamalısınız. Uygulamanızda değişen sabit ayarların yanı sıra değişen dinamik ayarlara ihtiyacınız varsa, yapılandırma sınıfınızın bitlerinin salt okunur olmamasına izin vermek yerine dinamik olanları işlemek için ayrı bir sınıfınız olmalıdır. .
İdeal olarak dosyayı programınızda tek bir yerde okursunuz, yani sadece bir " ConfigReader
" örneğiniz vardır . Ancak, Config örneğini ihtiyacınız olan yere iletmekle uğraşıyorsanız, ikinci bir ConfigReader'a sahip olmak global bir yapılandırma sunmaktan daha iyidir (ki tahmin ediyorum ki OP'nin "statik" "), bu da beni bir sonraki noktama getiriyor:
Singleton'un baştan çıkarıcı siren şarkısından kaçının: "Sizi o sınıf sınıfından geçirmek zorunda kalacağım, tüm inşaatçılarınız güzel ve temiz olacak. Devam edin, çok kolay olacak." Gerçek, iyi tasarlanmış test edilebilir bir mimariyle, Config sınıfını veya bir kısmını uygulamanızın birçok sınıfından geçirmeniz gerekmeyecektir. Üst düzey sınıfınızda, ana () işlevinizde veya her neyse bulacağınız şey, conf'i bileşen sınıflarınıza daha sonra bir araya getirdiğiniz argümanlar olarak sağlayacağınız bireysel değerlere çözersiniz (manuel bağımlılık) enjeksiyon). Tek bir / global / statik conf, birim testini uygulamanızı uygulamak ve anlamak için daha zor hale getirecektir - örneğin, yeni geliştiricileri ekibinize, şeyleri test etmek için küresel durumu ayarlamaları gerektiğini bilmeyecek şekilde karıştırır.
Diliniz özellikleri destekliyorsa, bu amaç için kullanmalısınız. Bunun nedeni, bir veya daha fazla ayara bağlı 'türetilmiş' yapılandırma ayarlarının eklenmesinin çok kolay olacağı anlamına gelir. Örneğin
int Prop1 { get; }
int Prop2 { get; }
int Prop3 { get { return Prop1*Prop2; }
Diliniz özellik deyimini yerel olarak desteklemiyorsa, aynı efekti elde etmek için bir geçici çözüm olabilir veya sadece bonus ayarlarını sağlayan bir sarıcı sınıfı oluşturursunuz. Aksi takdirde mülklerin faydasını sağlayamazsanız, manuel olarak yazmak ve sadece bazı OO-tanrıyı memnun etmek için alıcıları / ayarlayıcıları kullanmak zaman kaybıdır. Sade eski bir tarlada daha iyi olacaksın.
Öncelik sırasına göre farklı yerlerden birden fazla yapılandırmayı birleştirmek ve almak için bir sisteme ihtiyacınız olabilir. Bu öncelik sırası iyi tanımlanmalı ve tüm geliştiriciler / kullanıcılar tarafından anlaşılmalıdır, örn. HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE. Yapılandırmalarınızı salt okunur olarak saklayabilmeniz için bu işlevsel stili yapmalısınız:
final_conf = merge(user_conf, machine_conf)
ziyade:
conf.update(user_conf)
Son olarak, seçtiğiniz çerçeve / dil kendi yerleşik, iyi bilinen yapılandırma mekanizmalarını sağlıyorsa, bunu kendi başınıza döndürmek yerine kullanmanın faydalarını göz önünde bulundurmanız gerektiğine eklemeliyim.
Yani. Dikkate alınacak birçok özellik - doğru olsun ve uygulama mimarinizi derinden etkileyecek, hataları azaltacak, işleri kolayca test edilebilir hale getirecek ve sizi başka bir yerde iyi tasarım kullanmaya zorlayacak.