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。还有其他选择吗?
答案 0 :(得分: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();
}
}
}
当您的对象上的可能操作列表已知时,建议使用这种更简单的方法,以便您可以在接口的合同中引入所有操作。另一方面,访问者允许您在班级/界面上引入任意数量的操作,因为您只需提供新的具体访问者。