TypeOf子类的设计模式

时间:2012-03-04 22:10:17

标签: .net vb.net oop design-patterns reflection

我正在研究串行数据协议的解析器。我有一个总体Packet类,一些子类,如CommandPacketStatusPacket,然后是每个子类的几个子类:

  • 分组
    • CommandPacket
      • CommandTypeA
      • CommandTypeB
    • 状态包
      • StatusTypeA
      • StatusTypeB

Packet类有一个静态方法用于从缓冲区中获取数据,如果它表示有效数据包,则返回Packet类的新实例,并使用必要的数据进行实例化。 / p>

现在,这就是我出现问题的地方。我希望能够返回最具体的类型的数据包。为了实现这一点,我创建了一个静态.isValid()方法,该方法在子类上被重写。我的想法是,我可以遍历每种类型的特定数据包(CommandTypeACommandTypeBStatusTypeAStatusTypeB等),并调用.isValid(),直到其中一个他们返回TRUE。此时,我将返回该特定数据包类型的新实例。

当然,我可以直接创建此方法,如何解决未添加到项目中的数据包类型?我希望将来有人能够扩展我的课程,而无需修改原来的Packet课程。

我考虑过利用反射,但我避免使用它,因为这些方法会被收到的每个数据包调用,并且必须有效。

有关如何重新设计我的设计模式的想法吗?


虽然我认为它不完全与讨论相关,但我在VB.NET中这样做。此处发布的问题类似(但不完全相同):Java - subclass validation design pattern

2 个答案:

答案 0 :(得分:2)

基于评论和MarkJ的主角,这是一个建议(最终基于接口而不是强类型检查的属性):

public interface IPacketValidator
{
    bool IsPacketValid( Packet packet );
    Type PacketType { get; }
}

public class ValidatorsRegistry
{
    private List<IPacketValidator> m_validatorsList;

    private static ValidatorsRegistry m_Instance = new ValidatorsRegistry();
    public static ValidatorsRegistry Instance { get { return m_Instance; } }

    private ValidatorsRegistry()
    {
        InitValidatorsRegistry();
    }

    private void InitValidatorsRegistry()
    {
        m_validatorsList = new List<IPacketValidator>();

        Type iPacketValidatorType = typeof( IPacketValidator );

        foreach ( Assembly asm in AppDomain.CurrentDomain.GetAssemblies() )
        {
            foreach ( Type type in asm.GetTypes() )
            {
                if ( iPacketValidatorType.IsAssignableFrom( type ) && type != iPacketValidatorType )
                {
                    IPacketValidator validator = (IPacketValidator)Activator.CreateInstance(type);
                    m_validatorsList.Add( validator );
                }
            }
        }
    }

    public Type GetSpecificPacketType(Packet packet)
    {
        Type packetType = typeof( Packet );
        foreach ( IPacketValidator validator in m_validatorsList )
        {
            if ( validator.IsPacketValid( packet ) )
            {
                packetType = validator.PacketType;
                break;
            }
        }

        return packetType;
    }
}

答案 1 :(得分:1)

对于依赖注入容器或MEF,这是一个完美的用例。

但是回到这个问题,所以你需要同时具有Packet状态和能够在不设置此状态的情况下进行验证。这里有几种选择,既不完美:

  1. 将每个子类的一个实例作为模板,并询问每个实例是否可以使用给定数据克隆自身。缺点:没有静态保证模板不会作为实际实例传递。
  2. 将此逻辑移至单独的PacketFactory并允许多个工厂(用于可扩展性)。缺点:如果选择逻辑与数据包类型紧密耦合,它会创建两个真实来源。
  3. 使用当前的静态方法,并有一个Func<X, Packet>列表,如果Packet有效,Func将返回X个实例,如果不是null则返回{{1}} 。缺点:没有静态保证实现此方法。
  4. (仅为了完整性):与1相同,但创建模板绕过构造函数,以便这种对象在正常情况下不会被创建。缺点:黑客。
  5. 在所有这些情况下,可以使用自定义案例中的启动反射或使用所选DI框架提供的任何扩展机制来完成发现。