0
public interface IRecord
{

}

public class BirthRecord : IRecord
{
    public string CityOfBirth;
    public Date DateOfBirth;
    public BirthRecord(string cityOfBirth, Date dateOfBirth)
    {
        // assign these to properties
    }
}

public class CarRecord : IRecord
{
    public Color Color;
    public string Manufacturer;
    public CarRecord(Color color, string manufacturer)
    {
        // assign these to properties
    }
}

public interface IAccount
{
    public List<IRecord> Records { get; set; }
}

public class Client
{
    public void ProcessAccount(IAccount account)
    {
        foreach(IRecord record in account.Records)
        {
            if(record is CarRecord)
                handleCarRecord((CarRecord)record);
            else if(record is BirthRecord)
                handleBirthRecord((BirthRecord)record);
        }
    }
}

クライアントに到達して値オブジェクトを処理したい場合、あらゆる種類の厄介な型チェックとキャストを行う必要があります。これは受け入れられるパターンですか、それともより根本的な設計ミスを犯しているのでしょうか? これは、他の OOD 原則ではないにしても、OCP に違反しているようです。代替手段はありますか?

4

1 に答える 1

2

あなたが提示するアプローチはビジターパターンと呼ばれますが、ビジターは複雑なデータ構造に対して抽象的なアルゴリズムを作成するために使用されるため、テンプレートアルゴリズムがあり、その具体的な実装を提供するだけです。

public abstract class AbstractAccountVisitor {     

  public void ProcessAccount(IAccount account)     
  {          
     foreach(IRecord record in account.Records)         
     {             
         if(record is CarRecord)                 
             handleCarRecord((CarRecord)record);             
         else if(record is BirthRecord)                 
             handleBirthRecord((BirthRecord)record);         
     }     
  } 

  public abstract void handleCarRecord( CarRecord record );
  public abstract void handleBirthRecord( BirthRecord record );

} 

これにより、次のことが可能になります

public class ConcreteAccountVisitor : AbstractAccountVisitor {

    public override handleCarRecord( CarRecord record ) {
       // do something concrete with carrecord
    }

    public override handleBirthRecord( BirthRecord record ) {
       // do something concrete with birthrecord
    }

}

// client
AbstractAccountVisitor visitor = new ConcreteAccountVisitor();

visitor.ProcessAccount( account );

アルゴリズムのコアをベース ビジターにカプセル化することで、特定の種類のレコードを処理するメソッドをオーバーライドするだけで、処理をカスタマイズできることに注意してください。

また、ビジターを提供する代わりに、処理をクラスに導入することもできます。

public interface IRecord {
    void Operation();
}            

public class AccountProcessor {     

  public void ProcessAccount(IAccount account)     
  {          
     foreach(IRecord record in account.Records)         
     {             
         record.Operation();
     }     
  } 
} 

インターフェイスのコントラクトにすべての操作を導入できるように、オブジェクトで可能な操作のリストがわかっている場合は、このような簡単なアプローチをお勧めします。一方、ビジターを使用すると、新しい具体的なビジターを提供するだけで、クラス/インターフェースに任意の数の操作を導入できます。

于 2012-08-30T18:41:16.797 に答える