web-dev-qa-db-ja.com

同じ結果を与える複数のプロパティ/メソッド

組織のニーズに基づいて、同じプロパティへの複数の参照の使用がコードの匂い/アンチパターンであるかどうかを確認しようとしています。

例として、次のことを考慮してください。

abstract class Person {

    public string Title { get; set; }
    public string Forename { get; set; }
    public string MiddleNames { get; set; }
    public string Surname { get; set; }

    public string GivenName  { get { return Forename; } set { Forename = value; } }
    public string FamilyName { get { return Surname; }  set { Surname = value; } }
    public string FirstName  { get { return Forename; } set { Forename = value; } }
    public string LastName   { get { return Surname; }  set { Surname = value; } }

}

あなたが見ることができるように、私はいくつかの他のプロパティを持っています、(種類)オブジェクトのプロパティにエイリアスまたは代替名を付けますが、基本的には機能を正確に繰り返します例外なく基本プロパティの。

この背後にある理由は、組織のさまざまな領域で使用されている命名規則にあります。それは同じ情報をアドレス指定する複数の方法を提供し、それぞれの異なるエリアがそれぞれの好みのアクセス方法を使用できるようにします。他の各プロパティは基本プロパティを参照するため、プログラムによる変更は、基本プロパティに含めるだけで済みます。

そして明確にするために...

@GregBurghardtは私の難問に代わるものを親切に投稿してくれましたが、私の発言の1つをもう少し修飾する必要があると感じています。

VB.NETでは、インターフェースを自分のクラスに非常に楽しくコーディングできますが、実際のメンバーの実装では次のように別の名前を使用します...

Public Interface IPerson
    Property Forename() As String
    Property Surname() As String
End Interface

Public Class BillingPerson
    Implements IPerson

    Public Property GivenName() As String Implements IPerson.Forename
    ...
    Public Property FamilyName() As Int32 Implements IPerson.Surname
    ....
End Class

ここでは、(VB)プロパティに別のプロパティ名を使用していますが、インターフェイスの実際の名前(たとえばパブリックプロパティGivenName()As String- IPerson.Forenameを実装します)。これは、インターフェイスを使用して、明らかなプロパティ名の違いにもかかわらず、BillingPersonクラスを参照できることを意味します...

'Define our interface type object here...
Dim myP As IPerson = New BillingPerson()
'Assign values directly to the interface members...
myP.Forename = "Fred"
myP.Surname = "Bloggs"
'Output the interface members...
Console.WriteLine(myP.Forename & " " & myP.Surname)

...または元のクラスを直接参照できます。

'Define our BillingPerson object here...
Dim myP As BillingPerson
'Assign values directly to the interface members...
myP.GivenName = "Fred"
myP.FamilyName = "Bloggs"
'Output the interface members...
Console.WriteLine(myP.Forename & " " & myP.Surname)

この方法論を使用すると、私の問題は非常に短期間で済み、必要に応じてインターフェイスに基づいてクラスをいくつでも作成できます。

これはC#では同じように機能しないようですが、インターフェイスメンバーの名前に直接エイリアスを付けることはできません。

5
Paul

組織は名前の付け方に同意できないようなので、たくさんのものが存在すると想定してアプリケーションを設計する必要があるように感じますt同意する。悪化するだけのようです。

多分あなたが代わりに必要なのは、より多くのファサードまたはアダプターパターンを採用することです。

だから、ここにあなたの「標準的な」人があります:

public class Person
{
    public string Title { get; set; }
    public string Forename { get; set; }
    public string MiddleNames { get; set; }
    public string Surname { get; set; }

    // Enterprise wide behavior goes here
}

そして請求部門は独自の方法を持つことができます:

public class BillingDepartmentPerson
{
    private readonly Person person;

    public string GivenName
    {
        get { return person.Forename; }
        set { person.Forename = value; }
    }

    public string FamilyName
    {
        get { return person.Surname; }
        set { person.Surname = value; }
    }

    public string FirstName
    {
        get { return person.Forename; }
        set { person.Forename = value; }
    }

    public string LastName
    {
        get { return person.Surname; }
        set { person.Surname = value; }
    }

    public BillingDepartmentPerson(Person person)
    {
        this.person = person;
    }

    // Billing department specific behavior goes here
}

配送部門も同様です。

public class ShippingDepartmentPerson
{
    private readonly Person person;

    public string Title
    {
        get { return person.Title; }
        set { person.Title = value; }
    }

    public string Forename
    {
        get { return person.Forename; }
        set { person.Forename = value; }
    }

    public string MiddleNames
    {
        get { return person.MiddleNames; }
        set { person.MiddleNames = value; }
    }

    public string Surname
    {
        get { return person.Surname; }
        set { person.Surname = value; }
    }

    public ShippingDepartmentPerson(Person person)
    {
        this.person = person;
    }

    // Shipping department specific behavior goes here
}

はい、コードの繰り返しがいくつかありますが、「組織領域固有」の機能をカプセル化して、Personクラスの一般的なエンタープライズ全体の機能から分離する方法があります。

また、出荷部門のコンテキストで、請求部門に固有の操作を誤って呼び出すこともできません。それはあなたに素晴らしい 懸念の分離 を与えるので、これらの異なる領域のリファクタリングを分離することができ、リファクタリングジョブの影響を範囲内に制限することができます( Open/Closed Principal も参照) =)。


パウロはコメントしました:

これがVB.NETであった場合、問題にはならなかったでしょう。インターフェイスを使用して、すべてのメンバー名にエイリアスを付けることができたでしょう。しかし、そうではありません!

... VB.NETでは、次のようなことができます:Public Function x() As Boolean Implements IY.a. C#でこれを許可するものは何もありません。

C#は:

public class MyItems : IEnumerable<int>
{
    public IEnumerator<int> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    // Implement an interface method explicitly
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

VB.NETとC#は、まったく同じ共通言語ランタイムで実行されるまったく同じMSILコードにコンパイルされます。

C#とVB.NETは、Visual Studioと.NET Frameworkのバージョンを比較する限り、同じ機能をサポートしています。

7
Greg Burghardt

操作臭なのでコード臭ではありません。先に進む前に、これらの「組織のさまざまな領域」に全社的な命名規則に同意するよう依頼する必要があると思います。あなたは彼らのコミュニケーションの失敗に応えようとしているので、この遺産を正すことをこれまで以上に難しくしています。

期間を決めて、2週間以内に返答してください。彼らはおそらくそうしないでしょう。次に、任意の名前yoを選択し、それらを会社の標準として宣言します。

5
Martin Maat

notaliasプロパティを指定する必要があると思いますが、おそらく最も一般的なプロパティを選択し、xmlコメントにエイリアスをドキュメント化します。

/// <summary>
/// Gets person's first name also known as Forename.
/// </summary>
public string FirstName { get; set; }

誰もが同じことに対して複数のプロパティを使用する場合、次のようなプロパティを持つ配列とリストがあります。

public int Count { get; }
public int NumberOfItems { get; }
public int Length { get; }

維持するのが難しいだけでなく、学習曲線も急になります。それらが実際に同一であることを知るには、それらすべてを知る必要があります。とにかくエイリアスを使用したい場合は、いつでも独自の拡張機能を作成できます。

1
t3chb0t

別の方法として、名前と単一のプロパティを持つ単一クラスのアプローチを使用することもできますが、リフレクションを使用して汎用アクセサーを提供できます。

public static T GetPropertyValue<T>(object obj, string propName) 
{ 
    return (T)obj.GetType().GetProperty(propName).GetValue(obj, null); 
}

その前に、ルックアップ構成(xml、jsonなど)が必要です。

苗字

に変換されます:

次に、姓が反射メソッドに渡されます。したがって、ネーミングエイリアスは、コードや追加のクラスではなく、構成に格納されます。新しいエイリアスが追加された場合は、「エイリアス構成」を更新するだけです。

プロパティに直接アクセスするか、呼び出し側が独自の名前を使用してプロパティにアクセスできるようにする複雑なアプローチを使用して、コードは外観を反映し、リフレクティブメソッドを使用して値をプルします。

これにより、コードベースがクリーンに保たれます。リフレクションアクセスと直接アクセスの方が遅くなることに注意してください。

0
Jon Raynor