Recentemente, passei a preferir mapear relacionamentos 1-1 usando em Dictionaries
vez de Switch
instruções. Acho que é um pouco mais rápido escrever e mais fácil processar mentalmente. Infelizmente, ao mapear para uma nova instância de um objeto, não quero defini-lo assim:
var fooDict = new Dictionary<int, IBigObject>()
{
{ 0, new Foo() }, // Creates an instance of Foo
{ 1, new Bar() }, // Creates an instance of Bar
{ 2, new Baz() } // Creates an instance of Baz
}
var quux = fooDict[0]; // quux references Foo
Dada essa construção, desperdicei ciclos de CPU e memória criando 3 objetos, fazendo o que seus construtores pudessem conter, e acabei usando apenas um deles. Também acredito que o mapeamento de outros objetos fooDict[0]
nesse caso fará com que eles façam referência à mesma coisa, em vez de criar uma nova instância Foo
conforme pretendido. Uma solução seria usar um lambda:
var fooDict = new Dictionary<int, Func<IBigObject>>()
{
{ 0, () => new Foo() }, // Returns a new instance of Foo when invoked
{ 1, () => new Bar() }, // Ditto Bar
{ 2, () => new Baz() } // Ditto Baz
}
var quux = fooDict[0](); // equivalent to saying 'var quux = new Foo();'
Isso está chegando a um ponto em que é muito confuso? É fácil perder isso ()
no final. Ou o mapeamento para uma função / expressão é uma prática bastante comum? A alternativa seria usar um switch:
IBigObject quux;
switch(someInt)
{
case 0: quux = new Foo(); break;
case 1: quux = new Bar(); break;
case 2: quux = new Baz(); break;
}
Qual invocação é mais aceitável?
- Dicionário, para pesquisas mais rápidas e menos palavras-chave (maiúsculas e minúsculas)
- Alternar: Mais comumente encontrado no código, não requer o uso de um objeto Func <> para indireção.
fonte
fooDict[0] is fooDict[0]
). tanto com o lambda eo interruptor este não é o casoRespostas:
Essa é uma visão interessante do padrão de fábrica . Eu gosto da combinação do dicionário e da expressão lambda; isso me fez olhar para aquele contêiner de uma nova maneira.
Estou ignorando a preocupação em sua pergunta sobre os ciclos da CPU, como você mencionou nos comentários que a abordagem não lambda não fornece o que você precisa.
Acho que qualquer uma das abordagens (switch vs. Dictionary + lambda) vai ficar bem. A única limitação é que, usando o Dicionário, você está limitando os tipos de entradas que você pode receber para gerar a classe retornada.
O uso de uma instrução switch forneceria mais flexibilidade nos parâmetros de entrada. No entanto, se isso for um problema, você poderá agrupar o Dicionário dentro de um método e obter o mesmo resultado final.
Se for novo para sua equipe, comente o código e explique o que está acontecendo. Peça uma revisão do código da equipe, acompanhe-os sobre o que foi feito e informe-os. Fora isso, parece bom.
fonte
case 0: quux = new Foo(); break;
torna-secase 0: return new Foo();
o que é francamente tão fácil de escrever e muito mais fácil de ler do que{ 0, () => new Foo() }
O C # 4.0 fornece a
Lazy<T>
classe, que é semelhante à sua segunda solução, mas grita "Inicialização lenta" mais explicitamente.fonte
Estilisticamente, acho que a legibilidade é igual entre eles. É mais fácil fazer injeção de dependência com o
Dictionary
.Não esqueça que você deve verificar se a chave existe ao usar o
Dictionary
e deve fornecer um fallback, se não existir.Eu preferiria a
switch
instrução para caminhos de código estático eDictionary
para caminhos de código dinâmico (onde você pode adicionar ou remover entradas). O compilador pode executar algumas otimizações estáticas com oswitch
que não pode com oDictionary
.Curiosamente, esse
Dictionary
padrão é o que as pessoas às vezes fazem no Python, porque o Python não possui aswitch
declaração. Caso contrário, eles usam cadeias if-else.fonte
Em geral, eu preferiria nenhum.
Tudo o que está consumindo isso deve funcionar com a
Func<int, IBigObject>
. Em seguida, a fonte do seu mapeamento pode ser um dicionário ou um método que possui uma instrução switch, uma chamada de serviço da web ou alguma pesquisa de arquivo ... o que seja.Quanto à implementação, eu preferiria o Dicionário, pois é mais facilmente refatorado de 'dicionário de código rígido, chave de pesquisa, retornar resultado' para 'carregar dicionário do arquivo, chave de pesquisa, retornar resultado'.
fonte