ファイルから設定をどこにロードして保存するのですか?


9

この質問は、ファイルから設定をロードするほとんどのプログラムに当てはまると思います。私の質問はプログラミングの観点からです、そしてそれは実際にさまざまなクラスとアクセシビリティの観点からファイルから設定のロードを処理する方法です。例えば:

  • プログラムに単純なsettings.iniファイルがある場合、その内容をload()クラスのメソッド、またはおそらくコンストラクタにロードする必要がありますか?
  • 値をpublic static変数に格納する必要がありますか、それともstaticプロパティを取得および設定するメソッドが必要ですか?
  • ファイルが存在しないか、読み取りできない場合はどうなりますか?プログラムの残りの部分に、それらのプロパティを取得できないことをどのように知らせますか?

私はここの正しい場所でこれを求めていることを願っています。私はできるだけ質問を言語にとらわれないようにしたかったのですが、私は主に継承のようなものを持つ言語、特にJavaとC#.NETに焦点を合わせています。


1
.NETの場合、App.configとSystem.Configuration.ConfigurationManagerクラスを使用して設定を取得するのが最適です
Gibson

@Gibson私は.NETで始めたばかりなので、そのクラスの優れたチュートリアルにリンクしていただけませんか?
アンディ

Stackoverflowには多くの答えがあります。クイック検索で明らかになったのは、stackoverflow.com / questions / 114527 / stackoverflow.com/questions/13043530/…です。MSDNにも、msdn.microsoft.com / en-us / library / ms228063(v = vs.100).aspxおよびmsdn.microsoft.com/en-us/library/ms184658(v=vs.110).aspx
ギブソン

@ギブソンそれらのリンクをありがとう。彼らは非常に便利になります。
アンディ

回答:


8

これは実際には非常に重要な質問であり、ほとんどすべてのアプリケーションのコア部分であるにもかかわらず、十分に重要視されていないため、しばしば間違って行われます。これが私のガイドラインです:

すべての設定を含む構成クラスは、単純な古いデータ型struct / classでなければなりません。

class Config {
    int prop1;
    float prop2;
    SubConfig subConfig;
}

メソッドを持つ必要はなく、継承を伴うべきではありません(バリアントフィールドを実装するための言語での唯一の選択肢でない限り、次の段落を参照してください)。構成を使用して、設定をより小さな特定の構成クラス(上記のsubConfigなど)にグループ化できます。この方法で行う場合は、依存関係が最小限であるため、単体テストおよびアプリケーション全般で合格することが理想的です。

異なるセットアップの構成が異質である場合、バリアントタイプを使用する必要があるでしょう。値を読み取って正しい(サブ)構成クラスにキャストするときに、動的キャストを配置する必要があることは認められています。これは、別の構成設定に依存していることは間違いありません。

これを行うだけで、すべての設定をフィールドとして入力するのを怠ってはいけません。

class Config {
    Dictionary<string, string> values;
};

これは、どのフィールドを扱っているかを知る必要のない一般化されたシリアル化クラスを記述できることを意味するので魅力的ですが、それは間違っているので、その理由をすぐに説明します。

構成のシリアル化は、完全に別のクラスで行われます。これを行うために使用するAPIまたはライブラリが何であれ、シリアル化関数の本体には、基本的にはファイル内のパス/キーからオブジェクトのフィールドへのマップとなるエントリが含まれている必要があります。優れたイントロスペクションを提供し、すぐにこれを実行できる言語もあれば、明示的にマッピングを作成する必要がある言語もありますが、重要なことは、マッピングを一度だけ作成すればよいことです。たとえば、私がc ++ boostプログラムオプションパーサーのドキュメントから採用したこの抜粋を検討してください。

struct Config {
   int opt;
} conf;
po::options_description desc("Allowed options");
desc.add_options()
    ("optimization", po::value<int>(&conf.opt)->default_value(10);

最後の行は基本的に「最適化」がConfig :: optにマップすることを示しており、期待する型の宣言があることにも注意してください。タイプが予期したものではない場合、ファイル内のパラメーターが実際にはfloatまたはintでない場合、または存在しない場合、構成の読み取りを失敗させたいと考えています。つまり、ファイルのフォーマット/検証に問題があるため、ファイルを読み取るときに障害が発生し、except / returnコードをスローして正確な問題を報告する必要があります。これをプログラムの後半に遅らせることはできません。そのため、上記のように、すべてのディクショナリスタイルのConfをキャッチするように誘惑されるべきではありません。これは、ファイルが読み取られても失敗しない-値が必要になるまでキャストが遅延されるためです。

何らかの方法でConfigクラスを読み取り専用にする必要があります。クラスを作成してファイルから初期化するときに、クラスのコンテンツを一度設定します。アプリケーションで動的設定を変更する必要がある場合、および変更しないconst設定を使用する必要がある場合は、configクラスのビットを読み取り専用にしないで、動的設定を処理する別のクラスを用意する必要があります。 。

理想的には、プログラムの1つの場所でファイルを読み取る、つまり「ConfigReader」のインスタンスが1つしかない場合。ただし、Configインスタンスを必要な場所に渡すのに苦労している場合は、グローバル構成を導入するよりも2つ目のConfigReaderを用意することをお勧めします(これは、OPが「静的")、それは私を私の次のポイントに連れて行きます:

シングルトンの魅惑的なサイレンの歌は避けてください。「そのクラスクラスを渡す必要がなくなるので、すべてのコンストラクターが美しく、すっきりします。続ければ、とても簡単になります。」真実とは、Configクラスまたはその一部をアプリケーションの多くのクラスに渡す必要がほとんどない、適切に設計されたテスト可能なアーキテクチャです。あなたが見つけるもの、あなたのトップレベルのクラス、あなたのmain()関数、または何でも、あなたはそれらを一緒に戻す引数としてコンポーネントクラスに提供するであろう個々の値にconfを解明します(手動の依存関係)注入)。シングルトン/グローバル/静的confを使用すると、アプリケーションのユニットテストを実装および理解することがはるかに困難になります。たとえば、テストするためにグローバル状態を設定する必要があることを知らないチームの新規開発者を混乱させます。

言語がプロパティをサポートしている場合は、この目的でそれらを使用する必要があります。その理由は、1つ以上の他の設定に依存する「派生」構成設定を非常に簡単に追加できることを意味します。例えば

int Prop1 { get; }
int Prop2 { get; }
int Prop3 { get { return Prop1*Prop2; }

言語がプロパティイディオムをネイティブでサポートしていない場合は、同じ効果を達成するための回避策があるか、ボーナス設定を提供するラッパークラスを作成するだけです。プロパティの利点を他の方法で提供できない場合は、手動で記述し、単にオブジェクト指向の神を喜ばせる目的でゲッター/セッターを使用するのは時間の無駄です。あなたは平野の古いフィールドでより良くなるでしょう。

優先順位に従って、異なる場所から複数の構成をマージおよび取得するシステムが必要になる場合があります。この優先順位は明確に定義され、すべての開発者/ユーザーが理解できる必要があります。たとえば、WindowsレジストリHKEY_CURRENT_USER / HKEY_LOCAL_MACHINEを検討してください。構成を読み取り専用に保つことができるように、この機能的なスタイルを実行する必要があります。つまり、

final_conf = merge(user_conf, machine_conf)

のではなく:

conf.update(user_conf)

もちろん、選択したフレームワーク/言語が独自の組み込みのよく知られている構成メカニズムを提供する場合は、もちろん独自にロールするのではなく、それを使用する利点を検討する必要があります。

そう。考慮すべき多くの側面-正しく理解すると、アプリケーションアーキテクチャに大きな影響を与え、バグを減らし、テストが容易になり、他の場所で優れたデザインを使用するように強制します。


+1回答ありがとうございます。以前、ユーザー設定を保存したとき、の.iniようなファイルから読み取ったばかりなので、人間が読めるようになっていますが、変数を使用してクラスをシリアル化することを提案していますか?
アンディ

.iniは簡単に解析でき、.iniを可能な形式として含む多くのAPIもあります。このようなAPIを使用してテキスト解析の面倒な作業を行うことをお勧めしますが、最終的にはPODクラスを初期化する必要があります。ある形式からクラスのフィールドにコピーまたはフィールドを読み取るという一般的な意味で、シリアライズという用語を使用します。クラスをバイナリに、またはバイナリから直接シリアライズするより具体的な定義ではありません(通常、たとえばjava.io.Serializableとして理解されています)。 )。
ベネディクト

今、私は少しよく理解します。したがって、本質的には、すべてのフィールド/設定を含む1つのクラスがあり、ファイルからそのクラスの値を設定する別のクラスがあると言いますか?次に、他のクラスの最初のクラスから値を取得するにはどうすればよいですか?
アンディ

ケースバイケース。トップレベルのクラスの一部は、非常に多くのパラメーターに依存している場合、渡されるConfigインスタンス全体への参照が必要なだけかもしれません。他のクラスは1つまたは2つのパラメーターを必要とするだけかもしれませんが、それらをConfigオブジェクトに結合する必要はなく(テストをさらに簡単にします)、アプリケーションにいくつかのパラメーターを渡すだけです。私の回答で述べたように、テスト可能/ DI指向のアーキテクチャーで構築する場合、必要な場所で値を取得することは一般に難しくありません。危険にさらされているときにグローバルアクセスを使用してください。
ベネディクト

それで、継承を必要としない場合、configオブジェクトをクラスに渡すことをどのように提案しますか?コンストラクタを通じて?それで、プログラムのメインメソッドで、Configクラスに値を格納するリーダークラスが開始され、メインメソッドがConfigオブジェクトまたは個々の変数を他のクラスに渡しますか?
アンディ

4

一般的に(私の意見では)、アプリケーションに構成の格納方法を処理させ、構成をモジュールに渡すのが最善です。これにより、設定を保存する方法に柔軟性ができるため、ファイルまたはWebサービスまたはデータベースを対象としたり...

さらに、アプリケーションに「物事が失敗したときに何が起こるか」という重荷を負わせ、誰がその失敗が何を意味するのかを最もよく知っています。

また、ファイルシステムを操作したり、静的アクセスによって発生する同時実行性の問題に対処したりする必要がなく、構成オブジェクトを渡すだけの場合は、単体テストが非常に簡単になります。


回答ありがとうございますが、よくわかりません。私はアプリケーションを書くときに話しているので、構成を処理するものは何もないので、プログラマーとして、私は失敗の意味を知っています。
アンディ

@andy-もちろん、モジュールが構成に直接アクセスする場合、モジュールはどのコンテキストで作業しているかわからないため、構成の問題の処理方法を決定できません。アプリケーションがロードを実行している場合は、コンテキストを認識しているため、問題を処理できます。一部のアプリはデフォルト値にフェイルオーバーしたい場合もあれば、中止したい場合もあります
Telastyn

ここで明確にするために、モジュールとはクラスのことですか、それともプログラムの実際の拡張ですか?なぜなら、実際にコード内の設定をメインプログラムに保存するのに最適な場所と、他のクラスが設定にアクセスできるようにする方法を尋ねているからです。だから私は設定ファイルをロードしてからどこかに/何らかの方法で設定を保存したいので、ファイルを参照し続ける必要はありません。
アンディ

0

クラスのプログラミングに.NETを使用している場合、Resources、web.config、さらにはカスタムファイルなどのさまざまなオプションがあります。

Resourcesまたはweb.configを使用する場合、データは実際にはXMLファイルに格納されますが、ロードはより高速です。

これらのファイルからデータを取得して別の場所に保存することは、デフォルトでメモリにロードされるため、メモリの二重使用のようになります。

他のファイルまたはプログラミング言語については、Benedictによる上記の回答が機能します。


お返事ありがとうございます。返信が遅くなってすみません。リソースを使用することは良いオプションですが、同じプログラムを他の言語で開発するつもりであるので、XMLまたはJSONファイルを使用したいのですが、それがおそらく私にとって最良のオプションではないことに気づきました。同じファイルを他のプログラミング言語で読み取ることができるように、自分のクラスでそれを読み取ります。
アンディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.