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 回答