Фабричный метод аргумента CreateInstance не требуется для определенного подтипа

У меня есть фабричный класс и метод CreateInstance

CreateInstance(EntityModel.TipoEntitaTipoParametroEntita tipoParametroEntita, IParametroEntitaMultiValoreDataSourceProvider parametroEntitaMultiValoreDataSourceProvider)

Фабрика может создавать два разных подтипа в зависимости от значения tipoParametroEntita.TipoCampo.IdTipoCampo

Дело является вторым аргументом CreateInstance (parametroEntitaMultiValoreDataSourceProvider) используется только для создания экземпляра TipoEntitaTipoParametroEntitaMultiValore
тогда как не используется при создании экземпляра TipoEntitaTipoParametroEntitaSingoloValore

public class TipoEntitaTipoParametroEntitaFactory : ITipoEntitaTipoParametroEntitaFactory
{
    /// <summary>
    /// Creates an instance of TipoEntitaTipoParametroEntitaSingoloValore or  TipoEntitaTipoParametroEntitaMultiValore 
    /// </summary>
    public TipoEntitaTipoParametroEntita CreateInstance(EntityModel.TipoEntitaTipoParametroEntita tipoParametroEntita, IParametroEntitaMultiValoreDataSourceProvider parametroEntitaMultiValoreDataSourceProvider)
    {
        if (tipoParametroEntita.TipoCampo.IdTipoCampo == (int)EntityModel.Enum.TipoCampo.CampoLibero ||
            tipoParametroEntita.TipoCampo.IdTipoCampo == (int)EntityModel.Enum.TipoCampo.CampoLiberoMultiLinea)
        {
            return new TipoEntitaTipoParametroEntitaSingoloValore(tipoParametroEntita);
        }

        if (tipoParametroEntita.TipoCampo.IdTipoCampo ==
            (int)EntityModel.Enum.TipoCampo.DropdownListQueryDataSource ||
            tipoParametroEntita.TipoCampo.IdTipoCampo ==
            (int)EntityModel.Enum.TipoCampo.DropdownListTableDataSource)
        {
            return new TipoEntitaTipoParametroEntitaMultiValore(tipoParametroEntita,
                parametroEntitaMultiValoreDataSourceProvider);
        }

        return null;

    }
}

Я сомневаюсь в этом принятом шаблоне, так как мне всегда нужно передавать экземпляр IParametroEntitaMultiValoreDataSourceProvider даже если в этом нет необходимости и, кроме того, кто-то, читающий подпись метода, может подумать, что для создания любого типа TipoEntitaTipoParametroEntita экземпляр IParametroEntitaMultiValoreDataSourceProvider необходимо.

Какой будет лучший подход? Две разные фабрики? Только одна фабрика и два CreateInstance (один возвращающий TipoEntitaTipoParametroEntitaSingoloValore и другие TipoEntitaTipoParametroEntitaMultiValore)?

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

1 ответ

Решение

С точки зрения функционального программирования, я использую, чтобы смотреть на шаблон Visitor, когда имеешь дело с так называемыми "алгебраическими типами данных", то есть различными подтипами. Во всяком случае, я не всегда являюсь поклонником такого подхода, поскольку он может быть сложным в начале.

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

Теперь, в двух словах, классический способ добиться этого, используя функцию проверки типа языка C#, - определить нового посетителя, включая все различные переопределения вашего CreateInstance с подписями:

public IEntitaTipoParametroEntita CreateInstance(SubType1 subType1) 
{ 
   // ...
}

public IEntitaTipoParametroEntita CreateInstance(SubType2 subType2) 
{
    // ...
}

где каждый подтип должен иметь свой собственный

IEntitaTipoParametroEntita accept(CreateVisitor visitor) 
{
    visitor.CreateInstance(this);
}

Так что вы можете избежать if а также switch и аналогичные подверженные ошибкам синтаксисы проверки подтипов и просто вместо этого создают конкретный посетитель и просто передают его любому подтипу для обработки.

Таблицы БД

Если между подтипами есть существенная общность, то разделение подтипов на отдельные физические таблицы, вероятно, не имеет большого значения.

Поэтому, что касается проектирования БД, "таблица на иерархию" (которая использует столбец дискриминатора типа для хранения информации о типе), кажется, лучше подходит для вашего примера: он включает полиморфизм путем денормализации схемы SQL. Чтобы дать Entity Framework команду использовать эту стратегию, все, что требуется, это извлечь класс из DbContext класс и добавить DBSet свойство для супертипа, при этом не добавляя DBSet свойства для подтипов.

Чтение ссылок

Другие вопросы по тегам