Cara sederhana untuk menjaga pengaturan aplikasi Java diwakili oleh file teks dengan ekstensi ".properties" yang berisi pengidentifikasi setiap pengaturan yang terkait dengan nilai tertentu (nilai ini mungkin berupa angka, string, tanggal, dll.) . C # menggunakan pendekatan yang serupa, tetapi file teks harus dinamai "App.config". Dalam kedua kasus, dalam kode sumber Anda harus menginisialisasi kelas tertentu untuk pengaturan membaca: kelas ini memiliki metode yang mengembalikan nilai (sebagai string) yang terkait dengan pengidentifikasi pengaturan yang ditentukan.
// Java example
Properties config = new Properties();
config.load(...);
String valueStr = config.getProperty("listening-port");
// ...
// C# example
NameValueCollection setting = ConfigurationManager.AppSettings;
string valueStr = setting["listening-port"];
// ...
Dalam kedua kasus kita harus mengurai string yang dimuat dari file konfigurasi dan menetapkan nilai yang dikonversi ke objek yang diketik terkait (kesalahan penguraian dapat terjadi selama fase ini). Setelah langkah penguraian, kita harus memeriksa bahwa nilai pengaturan milik domain validitas tertentu: misalnya, ukuran maksimum antrian harus menjadi nilai positif, beberapa nilai mungkin terkait (misalnya: min <maks ), dan seterusnya.
Misalkan aplikasi harus memuat pengaturan segera setelah dimulai: dengan kata lain, operasi pertama yang dilakukan oleh aplikasi adalah memuat pengaturan. Setiap nilai yang tidak valid untuk pengaturan harus diganti secara otomatis dengan nilai default: jika ini terjadi pada sekelompok pengaturan terkait, semua pengaturan tersebut diatur dengan nilai default.
Cara termudah untuk melakukan operasi ini adalah dengan membuat metode yang mem-parsing semua pengaturan, kemudian memeriksa nilai yang dimuat dan akhirnya menetapkan nilai default apa pun. Namun pemeliharaan sulit jika Anda menggunakan pendekatan ini: karena jumlah pengaturan meningkat saat mengembangkan aplikasi, semakin sulit untuk memperbarui kode.
Untuk mengatasi masalah ini, saya berpikir untuk menggunakan pola Metode Templat , sebagai berikut.
public abstract class Setting
{
protected abstract bool TryParseValues();
protected abstract bool CheckValues();
public abstract void SetDefaultValues();
/// <summary>
/// Template Method
/// </summary>
public bool TrySetValuesOrDefault()
{
if (!TryParseValues() || !CheckValues())
{
// parsing error or domain error
SetDefaultValues();
return false;
}
return true;
}
}
public class RangeSetting : Setting
{
private string minStr, maxStr;
private byte min, max;
public RangeSetting(string minStr, maxStr)
{
this.minStr = minStr;
this.maxStr = maxStr;
}
protected override bool TryParseValues()
{
return (byte.TryParse(minStr, out min)
&& byte.TryParse(maxStr, out max));
}
protected override bool CheckValues()
{
return (0 < min && min < max);
}
public override void SetDefaultValues()
{
min = 5;
max = 10;
}
}
Masalahnya adalah bahwa dengan cara ini kita perlu membuat kelas baru untuk setiap pengaturan, bahkan untuk nilai tunggal. Apakah ada solusi lain untuk masalah seperti ini?
Singkatnya:
- Perawatan yang mudah: misalnya, penambahan satu atau lebih parameter.
- Extensibility: versi pertama aplikasi dapat membaca file konfigurasi tunggal, tetapi versi yang lebih baru dapat memberikan kemungkinan pengaturan multi-pengguna (admin mengatur konfigurasi dasar, pengguna hanya dapat mengatur pengaturan tertentu, dll.).
- Desain berorientasi objek.
sumber
Jawaban:
Pada dasarnya file konfigurasi eksternal dikodekan sebagai dokumen YAML. Ini kemudian diuraikan selama aplikasi start up dan dipetakan ke objek konfigurasi.
Hasil akhirnya kuat dan terutama mudah dikelola.
sumber
Mari kita pertimbangkan ini dari dua sudut pandang: API untuk mendapatkan nilai konfigurasi, dan format penyimpanan. Mereka sering terkait, tetapi sangat membantu untuk mempertimbangkannya secara terpisah.
API konfigurasi
Pola Metode Templat sangat umum, tetapi saya mempertanyakan apakah Anda benar-benar membutuhkan generalisasi itu. Anda membutuhkan kelas untuk setiap jenis nilai konfigurasi. Apakah Anda benar-benar memiliki banyak tipe? Saya kira Anda bisa bertahan hanya dengan segelintir: string, int, float, boolean, dan enum. Dengan ini, Anda dapat memiliki
Config
kelas yang memiliki beberapa metode di atasnya:(Saya pikir saya mendapatkan obat generik yang terakhir benar.)
Pada dasarnya setiap metode tahu bagaimana menangani parsing nilai string dari file konfigurasi dan untuk menangani kesalahan dan untuk mengembalikan nilai default jika sesuai. Pengecekan rentang untuk nilai numerik mungkin cukup. Anda mungkin ingin memiliki kelebihan yang menghilangkan nilai rentang, yang akan setara dengan menyediakan rentang Integer.MIN_VALUE, Integer.MAX_VALUE. Enum adalah cara yang aman untuk memvalidasi string terhadap serangkaian string yang ditetapkan.
Ada beberapa hal yang tidak ditangani, seperti beberapa nilai, nilai yang saling terkait, pencarian tabel dinamis, dll. Anda bisa menulis rutin parsing dan validasi untuk ini, tetapi jika ini menjadi terlalu rumit, saya akan mulai mempertanyakan apakah Anda mencoba melakukan terlalu banyak dengan file konfigurasi.
Format Penyimpanan
File properti Java tampak baik untuk menyimpan pasangan nilai kunci individual, dan mereka mendukung jenis nilai yang saya jelaskan di atas dengan cukup baik. Anda juga dapat mempertimbangkan format lain seperti XML atau JSON, tetapi ini mungkin berlebihan kecuali jika Anda memiliki data bersarang atau berulang. Pada titik itu tampaknya jauh melampaui file konfigurasi ....
Telastyn menyebutkan objek berseri. Ini adalah suatu kemungkinan, meskipun serialisasi memang memiliki kesulitannya. Ini biner, bukan teks, jadi sulit untuk melihat dan mengedit nilai. Anda harus berurusan dengan kompatibilitas serialisasi. Jika nilai tidak ada dari input serial (mis., Anda menambahkan bidang ke kelas Config dan Anda membaca bentuk serial lama dari itu), bidang baru diinisialisasi ke nol / nol. Anda harus menulis logika untuk menentukan apakah akan mengisi beberapa nilai default lainnya. Tetapi apakah nol menunjukkan tidak adanya nilai konfigurasi, atau apakah ditetapkan sebagai nol? Sekarang Anda harus men-debug logika ini. Akhirnya (tidak yakin apakah ini masalah) Anda masih mungkin perlu memvalidasi nilai dalam aliran objek serial. Itu mungkin (meskipun tidak nyaman) bagi pengguna jahat untuk memodifikasi aliran objek berseri tidak terdeteksi.
Saya akan mengatakan untuk tetap dengan properti jika memungkinkan.
sumber
Config
kelas dan menggunakan pendekatan yang diusulkan oleh Anda:getInt()
,getByte()
,getBoolean()
, dll .. Melanjutkan dengan ide ini, saya pertama kali membaca semua nilai-nilai dan saya bisa mengasosiasikan setiap nilai untuk bendera (flag ini salah jika masalah terjadi selama deserialization, misalnya kesalahan penguraian). Setelah itu, saya bisa memulai fase validasi untuk semua nilai yang dimuat dan mengatur nilai default apa pun.Bagaimana saya melakukannya:
Inisialisasi semuanya ke nilai default.
Mengurai file, menyimpan nilai saat Anda pergi. Tempat yang ditetapkan bertanggung jawab untuk memastikan nilai-nilai dapat diterima, nilai-nilai buruk diabaikan (dan dengan demikian mempertahankan nilai default.)
sumber
Jika yang Anda butuhkan adalah konfigurasi sederhana, saya ingin membuat kelas lama yang sederhana untuk itu. Ini menginisialisasi default, dan dapat diambil dari file oleh aplikasi melalui kelas serialisasi bawaan. Aplikasi kemudian membagikannya ke hal-hal yang membutuhkannya. Tidak ada keributan dengan parsing atau konversi, tidak main-main dengan string konfigurasi, tidak ada sampah casting. Dan itu membuat cara konfigurasi lebih mudah digunakan untuk skenario dalam kode di mana ia perlu disimpan / dimuat dari server atau sebagai preset, dan cara lebih mudah untuk digunakan dalam pengujian unit Anda.
sumber
Setidaknya di .NET, Anda dapat dengan mudah membuat objek konfigurasi yang sangat diketik sendiri - lihat artikel MSDN ini untuk contoh cepat.
Protip: bungkus kelas konfigurasi Anda dalam sebuah antarmuka dan biarkan aplikasi Anda membicarakannya. Memudahkan untuk menyuntikkan konfigurasi palsu untuk pengujian atau untuk keuntungan.
sumber
ConfigurationElement
kelas dapat mewakili sekelompok nilai, dan untuk nilai apa pun Anda dapat menentukan validator. Tetapi jika misalnya saya ingin mewakili elemen konfigurasi yang terdiri dari empat probabilitas, empat nilai probabilitas berkorelasi, karena jumlahnya harus sama dengan 1. Bagaimana cara memvalidasi elemen konfigurasi ini?