O StaticFactory no codecampServer é um padrão bem conhecido?
-
26-09-2019 - |
Pergunta
ATUALIZAÇÃO: Esta é uma duplicata deO StaticFactory no codecampServer é um padrão bem conhecido?
Solução
Editar: Observe que esta resposta foi dada antes que a pergunta fosse completamente alterada em uma edição. Por causa disso, agora se refere a coisas que estavam presentes apenas na questão, conforme declarado originalmente. Eu imploro seu perdão para todos os "ponteiros pendurados". :-)
Resposta curta:
Com o código que você postou, não vejo uma alternativa ao elenco para IFoo<T>
. Caso contrário, o compilador dará um aviso (pelo menos na minha máquina).
Resposta mais elaborada:
Seu código realmente precisa ser assim? Mais especificamente, você precisa do elenco em questão?
Suponho que você chamará seu método de fábrica mais ou menos assim:
var stringFoo = FooFactory.CreateFoo<string>();
Você precisa fornecer o parâmetro de modelo (string
neste caso) explicitamente porque não pode ser derivado de nenhum argumento do método (neste caso, porque na verdade não há nenhum). Obviamente, o método da fábrica retornará um IFoo<string>
.
Agora, como você precisa especificar explicitamente o tipo em tempo de execução, você pode escrever:
var stringFoo = StringFoo.Create();
e, portanto, tem um método de fábrica dentro StringFoo
, assim, que incondicionalmente faz o óbvio:
public class StringFoo : IFoo<string>
{
...
public static StringFoo Create() // or alternatively, return an IFoo<string>
{
return new StringFoo();
}
}
Aplicando este padrão a outro IFoo<T>
As implementações também, isso salvará o você if
cadeia ou switch
Bloqueie dentro FooFactory.CreateFoo<T>
, Facilite seu código e se livre da necessidade de lançar (com o qual você está preocupado).
Não me interpretem mal, estou ciente de que os métodos de fábrica que suportam mais de um tipo de objeto são Útil em alguns casos; Mas parece que, no seu caso, causa mais problemas do que vale a pena.
PS: Você pode encontrar um aspecto de alguns contêineres do COI interessante. Eles geralmente precisam ser configurados, e isso abrange um processo em que você registra tipos de concreto (ou seja, classes de implementação) para interfaces abstratas; por exemplo (aqui usando Autofac):
var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();
Mais tarde, você pode solicitar uma instância de objeto de um tipo abstrato:
using (var container = builder.Build())
{
var stringFoo = container.Resolve<IFoo<string>>();
...
}
o Resolve
O método é a parte interessante. Você fornece um tipo abstrato e, usando os tipos registrados, ele retornará um objeto concreto do tipo StringFoo
. Olhe para ele, se não parecer exagerado para você! :-)
Outras dicas
Você pode descrever o problema que está resolvendo com esse mecanismo? Provavelmente há uma maneira mais clara de abordá -lo.
Editar
E sim, o código cheira. Você deixou a sala aberta para qualquer tipo, exceto que a restringe a um único tipo e gera uma exceção em tempo de execução. Por que ter um parâmetro de tipo nesse caso?
Você poderia tentar algo assim ...
public static class FooFactory
{
private static readonly Dictionary<Type, Type> FooTypesLookup;
static FooFactory()
{
FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes()
let fooInterface =
type.GetInterfaces().FirstOrDefault(
x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>))
where fooInterface != null
let firstTypeArgument = fooInterface.GetGenericArguments().First()
select new { Type = type, TypeArgument = firstTypeArgument })
.ToDictionary(x => x.TypeArgument, x => x.Type);
}
public static IFoo<T> CreateFoo<T>()
{
var genericArgumentType = typeof(T);
Type closedFooType;
return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType)
? (IFoo<T>) Activator.CreateInstance(closedFooType)
: null;
}
}
Ou melhor ainda, apresente seu contêiner IOC favorito (Windsor, mapa de estrutura, etc.) e registre todos os tipos que implementam o IFOO lá e resolvam -os quando necessário no lugar do ativador.CreateInstance Call.