0

私たちのシステムには、ボグ標準関連の poco の集まりであるドメインがあり、NHibernate とすべての遅延読み込みなどを使用して、オブジェクト データをハイドレートして永続化します。

ドメインに構造があるとしましょう。(これは私がその場で作成した純粋な例です)

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string Postcode { get; set; }
    public Region Region { get; set; }
}

public class Region
{
    public int Id { get; set; }
    public string Name { get; set; }
    public CountryCode CountryCode { get; set; }
}

public class CountryCode
{
    public string Name { get; set; }
    public string Code { get; set; }
    public CostCode CostCode { get; set; }
}

public class CostCode
{
    public string Name { get; set; }
    public string Description { get; set; }
}

ここで、Customer が自分自身の CostCode.Name 値の Name を取得したいとします。Customer にこれを行うメソッドを用意したほうがよいでしょうか。

    public string GetCountryCostName()
    {
        return Address.Region.CountryCode.CostCode.Name; 
    }

または、そうする方が良いでしょうか Customer と他のオブジェクトには、そのような情報を取得する機能があります

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }

    public string GetCountryCostName()
    {
        return Address.GetCountryCostCodeName();
    }
}

public class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string Postcode { get; set; }
    public Region Region { get; set; }

    public string GetCountryCostCodeName()
    {
        return Region.GetCountryCostCodeName();
    }
}

public class Region
{
    public int Id { get; set; }
    public string Name { get; set; }
    public CountryCode Country { get; set; }

    public string GetCountryCostCodeName()
    {
        return Country.GetCostCodeName();
    }

}

public class CountryCode
{
    public string Name { get; set; }
    public string Code { get; set; }
    public CostCode CostCode { get; set; }

    public string GetCostCodeName()
    {
        return CostCode.Name;
    }
}

public class CostCode
{
    public string Name { get; set; }
    public string Description { get; set; }
}

最初の方法では、Nhibernate は単一の SQL を作成して、作成するすべてのプロキシをハイドレートしますが、2 番目の方法では、遅延読み込みが NHibernate でどのように機能するかが正しい場合、関数がアクセスされると、より小さな SQL ステートメントが多数作成されます。では、オブジェクト指向の設計とパフォーマンスの観点から、どの方法が最善のアプローチでしょうか?

よろしく

CD

4

1 に答える 1

2

SQL と「コードの実行方法」の観点からは、2 つのアプローチは同一です。Hibernate は、 を含むメソッドに対して特別なオーバーライドを作成しませんでしたAddress.Region.CountryCode.CostCode.Name。それには、NHibernate 側でかなり複雑なコードのイントロスペクションが必要になります。代わりに、各many-to-oneプロパティは遅延読み込みプロキシ オブジェクトで設定されます。プロキシ オブジェクトの非 id プロパティにアクセスすると、NHibernate はオブジェクトがデータベースから初期化されていることを確認します。

デザインの観点から、あなたが求めているのは、デメテルの法則の本質です。デメテルの法則によれば、各クラスがすぐ隣のクラスとのみ会話する 2 番目のオプションの方が優れています。ただし、問題の両側には長所と短所があります。詳細については、ウィキペディアの記事を参照してください。

重要なポイントは、特定の変更によって影響を受けるコードの量を最小限に抑えることだと思います。その値にアクセスする方法について、そのチェーンの途中で何かを変更する必要がある場合、変更する必要があるのはクラスの半分だけです。ただし、この情報を実際に必要とするクラスは Customer だけだとします。その場合、デメテルの法則を無視して、最初のオプションを使用する方が良いと思います。はい、残りのデータ構造について顧客に深い知識を提供していますが、その構造が変更された場合、顧客のその 1 つのメソッドを変更するだけでよく、残りはそのままにしておきます。

null 値の場合、特にデータベースでこれらの値に null が許可されている場合は、それを例外処理に任せたくありません。オプション#1に対してこれを行う方が良いでしょう:

public virtual string GetCountryCostName()
{
    if (Address == null || Address.Region == null || Address.Region.CountryCode == null || Address.Region.CountryCode.CostCode == null)
        return null;
    return Address.Region.CountryCode.CostCode.Name; 
}

オプション #2 の場合:

public virtual string GetCostCodeName()
{
    if (Address == null)
        return null;
    return Address.GetCostCodeName();
}

// etc...

これらすべての関係がNOT NULLデータベース内の外部キーによって強制される必要がある場合は、チェックをスキップすることを選択できますif (... == null)。そのシナリオで null に遭遇することは実際には例外的なケースであり、それが例外の目的であるためです。

PS私はこの答えが本当に好きです。

于 2013-10-17T15:32:43.887 に答える