Recebi uma revisão de código de um desenvolvedor sênior hoje perguntando "A propósito, qual é a sua objeção a enviar funções por meio de uma declaração de switch?" Eu já li em muitos lugares sobre como bombear um argumento através da opção de alternar para chamar métodos é ruim OOP, não tão extensível, etc. No entanto, não consigo realmente encontrar uma resposta definitiva para ele. Eu gostaria de resolver isso para mim de uma vez por todas.
Aqui estão nossas sugestões de códigos concorrentes (php usado como exemplo, mas pode ser aplicado de maneira mais universal):
class Switch {
public function go($arg) {
switch ($arg) {
case "one":
echo "one\n";
break;
case "two":
echo "two\n";
break;
case "three":
echo "three\n";
break;
default:
throw new Exception("Unknown call: $arg");
break;
}
}
}
class Oop {
public function go_one() {
echo "one\n";
}
public function go_two() {
echo "two\n";
}
public function go_three() {
echo "three\n";
}
public function __call($_, $__) {
throw new Exception("Unknown call $_ with arguments: " . print_r($__, true));
}
}
Parte de seu argumento era "Ele (alternar método) tem uma maneira muito mais limpa de lidar com casos padrão do que o que você possui no método mágico genérico __call ()".
Discordo da limpeza e, de fato, prefiro telefonar, mas gostaria de ouvir o que os outros têm a dizer.
Argumentos que posso apresentar em apoio ao Oop
esquema:
- Um pouco mais limpo em termos do código que você precisa escrever (menos, mais fácil de ler, menos palavras-chave a serem consideradas)
- Nem todas as ações delegadas a um único método. Não há muita diferença na execução aqui, mas pelo menos o texto é mais compartimentado.
- Na mesma linha, outro método pode ser adicionado em qualquer lugar da classe, em vez de em um local específico.
- Os métodos são namespaced, o que é bom.
- Não se aplica aqui, mas considere um caso em que
Switch::go()
operado em um membro em vez de um parâmetro. Você precisaria alterar o membro primeiro e depois chamar o método PoisOop
você pode chamar os métodos de forma independente a qualquer momento.
Argumentos que posso apresentar em apoio ao Switch
esquema:
- Por uma questão de argumento, método mais limpo de lidar com uma solicitação padrão (desconhecida)
- Parece menos mágico, o que pode fazer com que desenvolvedores desconhecidos se sintam mais confortáveis
Alguém tem algo a acrescentar para ambos os lados? Eu gostaria de ter uma boa resposta para ele.
fonte
Oop
permite ter phpdoc para descrever cada método, que pode ser analisado por alguns IDEs (por exemplo, NetBeans).Respostas:
Uma mudança é considerada não POO, porque muitas vezes o polimorfismo pode fazer o truque.
No seu caso, uma implementação OOP poderia ser esta:
fonte
para este exemplo:
OK, apenas brincando aqui. O argumento a favor / contra o uso de uma instrução switch não pode ser fortemente formulado com um exemplo tão trivial, porque o lado OOP depende da semântica envolvida, não apenas do mecanismo de despacho .
As instruções de troca geralmente são uma indicação de classes ou classificações ausentes, mas não necessariamente. Às vezes, uma instrução switch é apenas uma instrução switch .
fonte
Talvez não seja uma resposta, mas no caso do código não alternativo, parece que seria uma correspondência melhor:
Uma grande parte do quebra-cabeça para avaliar é o que acontece quando você precisa criar
NewSwitch
ouNewOop
. Seus programadores precisam passar por um método ou outro? O que acontece quando suas regras mudam etc.fonte
is_callable
, mas deixei o call_user_func desde (não faz parte desta pergunta), pode haver outros argumentos a serem transmitidos. Mas agora que isso tenha se moveu para programadores, eu definitivamente concordo que @ resposta de Andrea é muito melhor :)Em vez de apenas colocar seu código de execução em funções, implemente um padrão de comando completo e coloque cada um deles em sua própria classe que implementa uma interface comum. Esse método permite que você use o IOC / DI para conectar os diferentes "casos" da sua classe e permite adicionar e remover facilmente casos do seu código ao longo do tempo. Também fornece um bom código que não viola os princípios de programação do SOLID.
fonte
Eu acho que o exemplo é ruim. Se houver uma função go () que aceite o argumento $ where, se é perfeitamente válido usar switch na função. A função go () única facilita a modificação do comportamento de todos os cenários go_where (). Além disso, você preservará a interface da classe - se você usar vários métodos, estará modificando a interface da classe com cada novo destino.
Na verdade, mudar não deve ser substituído por um conjunto de métodos, mas por um conjunto de classes - isso é polimorfismo. Em seguida, o destino será tratado por cada subclasse e haverá um método go () único para todos eles. Substituir condicional por polimorfismo é uma das refatorações básicas, descritas por Martin Fowler. Mas você pode não precisar de polimorfismo, e mudar é o caminho a seguir.
fonte
go()
, poderá facilmente violar o princípio da Substituição de Liskov. Se você está adicionando mais funcionalidade parago()
, você não deseja alterar a interface, tanto quanto eu sou concerend.