Шаблон проектирования для подкласса TypeOf - PullRequest
2 голосов
/ 05 марта 2012

Я работаю над парсером для протокола последовательных данных. У меня есть всеобъемлющий класс Packet, пара подклассов, таких как CommandPacket и StatusPacket, а затем несколько подклассов каждого из них:

  • Пакет
    • CommandPacket
      • CommandTypeA
      • CommandTypeB
    • Пакет статуса
      • StatusTypeA
      • StatusTypeB

Класс Packet имеет статический метод для извлечения данных из буфера, и, если он представляет действительный пакет, возвращает новый экземпляр класса Packet, созданный с необходимыми данными.

Теперь вот моя проблема. Я хотел бы иметь возможность вернуть самый специфический тип пакета. Чтобы облегчить это, я создал статический метод .isValid(), который переопределяется на подклассах. Идея состоит в том, что я мог бы перебирать каждый тип определенного пакета (CommandTypeA, CommandTypeB, StatusTypeA, StatusTypeB и т. Д.), Вызывая .isValid(), пока один из них не вернет TRUE. В этот момент я бы вернул новый экземпляр этого конкретного типа пакета.

Хотя, конечно, я могу создать этот метод напрямую, как мне учесть типы пакетов, которые еще не добавлены в мой проект? Я хочу, чтобы в будущем кто-то смог продлить мой класс без необходимости изменять исходный класс Packet.

Я подумал об использовании отражения для этого, но избегаю его, поскольку эти методы будут вызываться для каждого полученного пакета и должны быть эффективными.

Есть мысли о том, как мне переделать мой шаблон проектирования?


Хотя я не думаю, что это полностью соответствует обсуждению, я делаю это в VB.NET. Здесь также есть похожий (но не совсем тот же) вопрос: Java - шаблон проектирования валидации подкласса

Ответы [ 2 ]

2 голосов
/ 05 марта 2012

Основываясь на комментариях и рекомендации 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 голос
/ 05 марта 2012

Это идеальный вариант использования контейнера ввода зависимостей или MEF, я бы сказал.

Но вернемся к вопросу, поэтому вам нужно иметь и Packet с состоянием, и возможность проверки без установки этого состояния.Здесь есть несколько вариантов, ни один из которых не идеален:

  1. Создайте один экземпляр каждого подкласса в качестве шаблона и спросите каждый экземпляр, может ли он клонировать себя с данными данными.Недостаток: нет статических гарантий того, что шаблон не будет передан как фактический экземпляр.
  2. Переместите эту логику в отдельную PacketFactory и разрешите более одной фабрики (для расширяемости).Недостаток: если логика выбора тесно связана с типом пакета, она создает два источника правды.
  3. Используйте статический метод, как вы это делаете в настоящее время, и получите список Func<X, Packet>, где Func вернет Packetэкземпляр, если X является действительным или null, если это не так.Недостаток: нет статических гарантий, что этот метод реализован.
  4. (просто для полноты): то же самое, что и 1, но создайте шаблон в обход конструктора, чтобы этот тип объекта не мог быть создан в обычной ситуации.Недостаток: взлом.

Во всех этих случаях обнаружение может быть выполнено либо с помощью отражения при запуске в пользовательском случае, либо с любыми механизмами расширения, предоставляемыми выбранной структурой DI.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...