evitando if

votos
34

Eu estava pensando sobre o design orientado a objeto hoje, e eu queria saber se você deve evitar se declarações. Meu pensamento é que, em qualquer caso em que você precisar de uma declaração se você pode simplesmente criar dois objetos que implementam o mesmo método. As duas implementações de método seria simplesmente os dois possíveis ramos do original se comunicado.

Sei que isso parece extremo, mas parece que você poderia tentar argumentar que até certo ponto. Quaisquer pensamentos sobre isso?

EDITAR

Uau, que não demorou muito. Acho que isso é muito extremo. É possível dizer, porém, que sob OOP você deve esperar maneira menos if?

SEGUNDA EDIÇÃO

E quanto a isto: Um objeto que determina a sua implementação do método baseado em seus atributos. Isso quer dizer que você pode implementar someMethod()de duas maneiras e especificar algumas restrições. Em qualquer ponto de um objecto vai rota para a implementação do método correcto com base nas suas propriedades. Assim, no caso de if(x > 5)apenas tem dois métodos que dependem do xatributo

Publicado 26/08/2009 em 22:21
fonte usuário
Em outras línguas...                            


24 respostas

votos
32

Posso dizer-lhe uma coisa. Não importa o que as pessoas dizem, pensando em simplificar e eliminar a ramificação desnecessária é um sinal de que você amadurecer como um desenvolvedor de software. Existem muitas razões pelas quais ramificação é ruim, testes, manutenção, maior taxa de erros e assim por diante. Esta é uma das coisas que eu procuro quando entrevistando pessoas e é um excelente indicador de quão maduro que eles são como um desenvolvedor. Eu incentivá-lo a manter a experimentar, simplificando seu código e design usando menos condições. Quando eu fiz essa opção eu achei muito menos tempo de depuração meu código, ele simplesmente funcionou, então quando eu tive que mudar alguma coisa, as variações foram super fácil de fazer já que a maioria do código foi seqüencial. Mais uma vez eu incentivá-lo 100% para continuar fazendo o que está fazendo, não importa o que as outras pessoas dizem. Tenha em mente a maioria dos desenvolvedores estão trabalhando e pensando a nível muito mais baixo e apenas seguir as regras. Assim bom trabalho trazendo isso.

Respondeu 29/05/2011 em 18:08
fonte usuário

votos
12

Explicar como implementar o seguinte, sem uma instrução if ou a lógica ternária:

if ( x < 5 ) {
   x = 0
} else {
   print x;
}
Respondeu 26/08/2009 em 22:23
fonte usuário

votos
8

Eliminando completamente se as declarações não é realista e eu não acho que isso é o que Ori está sugerindo. Mas que muitas vezes pode ser substituído usando polimorfismo. (E por isso pode muitas declarações switch).

Francesco Cirillo iniciou a Campanha Anti-Se de sensibilização para esta questão. Ele diz:

Saber como usar objetos permite aos desenvolvedores eliminar FI com base no tipo, aqueles que mais frequentemente comprometer a flexibilidade e capacidade de evoluir de software.

Você ou sua equipe também pode aderir à campanha .

Respondeu 26/08/2009 em 22:33
fonte usuário

votos
8

Sim, é verdade que condicionais muitas vezes complexas podem ser simplificadas com polymorphishm. Mas não é útil o tempo todo. Vá ler o livro Refactoring de Fowler para ter uma idéia de quando.

http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html

Respondeu 26/08/2009 em 22:30
fonte usuário

votos
6

Um dos meus professores costumava dizer isso. I tendem a pensar que as pessoas ser tão dogmática sobre esse tipo de coisa geralmente não fazer programa para viver.

Respondeu 26/08/2009 em 23:05
fonte usuário

votos
5

Evitando Se Declaração: Há muitas maneiras de fazer, uma delas está abaixo:

int i=0;
if(i==1)
{
//Statement1
}

if(i==2)
{
//Statement2
}

if(i==3)
{
//Statement3
}

if(i==4)
{
//Statement4
}

Usando dicionário e delegado:

delegate void GetStatement ();

Dictionary<int,GetStatement > valuesDic=new Dictionary<int,GetStatement >();

void GetStatement1()
{
//Statement1
}
void GetStatement2()
{
//Statement2
}
void GetStatement3()
{
//Statement3
}


void GetStatement4()
{
//Statement4
}

void LoadValues()
{
valuesDic.Add(1,GetStatement1);
valuesDic.Add(2,GetStatement2);
valuesDic.Add(3,GetStatement3);
valuesDic.Add(4,GetStatement4);

}

Substituindo Se Declaração:

int i=0;
valuesDic[i].Invoke();
Respondeu 15/04/2012 em 16:47
fonte usuário

votos
5

Ter um olhar para a Campanha Anti-Se A ideia não é substituir cada caso em seu aplicativo com o padrão de estratégia ou Estado. A idéia é que quando você tem a lógica de ramificação complexa especialmente com base em algo como uma enumeração, você deve olhar para refatoração para o padrão de estratégia.

E nesse caso, você pode remover a se todos juntos usando uma fábrica. Aqui está um exemplo relativamente simples. Claro que como eu disse em um caso real, a lógica em suas estratégias seria um pouco mais complexo do que apenas imprimir "Eu sou ativo".

public enum WorkflowState
{
  Ready,
  Active,
  Complete
}

public interface IWorkflowStrategy
{
  void Execute();
}

public class ActiveWorkflowStrategy:IWorkflowStrategy
{
  public void Execute()
  {
    Console.WriteLine("The Workflow is Active");
  }
}

public class ReadyWorkflowStrategy:IWorkflowStrategy
{
  public void Execute()
  {
    Console.WriteLine("The Workflow is Ready");
  }
}

public class CompleteWorkflowStrategy:IWorkflowStrategy
{
  public void Execute()
  {
    Console.WriteLine("The Workflow is Complete");
  }
}

public class WorkflowStrategyFactory
{
  private static Dictionary<WorkflowState, IWorkflowStrategy> _Strategies= 
    new Dictionary<WorkflowState, IWorkflowStrategy>();
  public WorkflowStrategyFactory()
  {
    _Strategies[WorkflowState.Ready]=new ReadyWorkflowStrategy();
    _Strategies[WorkflowState.Active]= new ActiveWorkflowStrategy();
    _Strategies[WorkflowState.Complete = new CompleteWorkflowStrategy();
  }
  public IWorkflowStrategy GetStrategy(WorkflowState state)
  {
    return _Strategies[state];
  }
}

public class Workflow
{
    public Workflow(WorkflowState state)
    {
        CurrentState = state;
    }
    public WorkflowState CurrentState { get; set; }
}

public class WorkflowEngine
{
    static void Main(string[] args)
    {
        var factory = new WorkflowStrategyFactory();
        var workflows =
            new List<Workflow>
                {
                    new Workflow(WorkflowState.Active),
                    new Workflow(WorkflowState.Complete),
                    new Workflow(WorkflowState.Ready)
                };
        foreach (var workflow in workflows)
        {
            factory.GetStrategy(workflow.CurrentState).
                Execute();
        }
    }
}   
Respondeu 26/08/2009 em 23:08
fonte usuário

votos
4

De certa forma isso pode ser uma boa idéia. Swiching em um campo de tipo dentro de um objeto é geralmente uma má idéia quando você pode usar functtions virtuais em seu lugar. Mas o mecanismo de função virtual é de nenhuma maneira a intenção de substituir o teste if () em geral.

Respondeu 26/08/2009 em 22:27
fonte usuário

votos
3

Em resposta à pergunta de ifTrue:

Bem, se você tem aulas abertas e um suficientemente forte sistema de tipo dependente, é fácil, se um bocado parvo. Informalmente e em nenhum idioma específico:

class Nat {
    def cond = {
        print this;
        return this;
    }
}

class NatLessThan<5:Nat> { // subclass of Nat
    override cond = {
        return 0;
    }
}

x = x.cond();

(contínuo...)

Ou, sem aulas abertas, mas assumindo múltiplas expedição e classes anônimas:

class MyCondFunctor {
    function branch(Nat n) {
        print n;
        return n;
    }

    function branch(n:NatLessThan<5:Nat>) {
        return 0;
    }
}

x = new MyCondFunctor.branch(x);

Ou, como antes, mas com classes anônimas:

x = new {
    function branch(Nat n) {
        print n;
        return n;
    }

    function branch(n:NatLessThan<5:Nat>) {
        return 0;
    }
}.branch(x);

Você teria um tempo muito mais fácil se você reformulado essa lógica, é claro. Lembre-se que existem sistemas de tipo totalmente Turing-completos.

Respondeu 26/08/2009 em 22:44
fonte usuário

votos
3

Depende do que a declaração original está comparando. Minha regra de ouro é que se é um switchou iftestando a igualdade contra uma enumeração, então isso é um bom candidato para um método separado. No entanto, switche ifinstruções são utilizados por muitos, muitos outros tipos de testes - não há nenhuma boa maneira de substituir os operadores relacionais ( <, >, <=, >=) com métodos especializados, e alguns tipos de testes enumerados funcionar muito melhor com as declarações padrão.

Então você só deve substituir ifs se parecer com isto:

if (obj.Name == "foo" || obj.Name == "bar") { obj.DoSomething(); }
else if (obj.Name == "baz") { obj.DoSomethingElse(); }
else { obj.DoDefault(); }
Respondeu 26/08/2009 em 22:28
fonte usuário

votos
3

Como você decide qual objeto do método a ser usado sem um if?

Respondeu 26/08/2009 em 22:23
fonte usuário

votos
2
Assume we have conditional values.

public void testMe(int i){

if(i=1){
somevalue=value1;
}


if(i=2){
 somevalue=value2;
}

if(i=3){
somevalue=value3;
}

}

//**$$$$$you can replace the boring IF blocks with Map.$$$$$**

// ================================================ ============

Same method would look like this:
--------------------------------
public void testMe(int i){

Map<Integer,String> map = new HashMap<Integer,String>();

map.put(1,value1);
map.put(2,value2);
map.put(3,value3);

}
This will avoid the complicated if conditions.

Você pode usar a solução simliar ao usar padrões de fábrica para as classes de carga.

public void loadAnimalsKingdom(String animalKingdomType)
    if(animalKingdomType="bird"){
    Bird b = new Bird();
    }
    if(animalKingdomType="animal"){
    Animal a= new Animal();
    }
    if(animalKingdomType="reptile"){
    Reptile r= new Reptile();
    }
  }

Agora usando mapa:

   public void loadAnimalsKingdom(String animalKingdomType)
    {
       Map <String,String> map = new HashMap<String,String>();

       map.put("bird","com.animalworld.Bird.Class");
       map.put("animal","com.animalworld.Animal.Class");
       map.put("reptile","com.animalworld.Reptile.Class");

       map.get(animalKingdomType);

***Use class loader to load the classes on demand once you extract the required class from the map.***
}

Como a solução? Dá os polegares-up. - Vv

Respondeu 28/07/2017 em 06:04
fonte usuário

votos
2

Criando uma nova classe para um else, embora tecnicamente factível, provavelmente resultaria em código que é difícil de ler, manter, ou até mesmo a ser corretas.

Respondeu 26/08/2009 em 22:24
fonte usuário

votos
1

Eu acho que ele está dizendo ou o que ele quer dizer é que ele acha que é melhor para evitar o excesso de abuso de "marcação" e adicionar funcionalidade personalizada para uma classe por vários if quando ele melhor faz sentido a subclasse ou repensar o objeto hierarquia.

Respondeu 26/08/2009 em 22:26
fonte usuário

votos
1

É uma ideia interessante. Eu acho que você poderia , teoricamente, fazer isso, mas seria uma enorme dor em uma linguagem não especificamente concebido para apoiá-lo. Eu certamente não vejo nenhuma razão para isso.

Respondeu 26/08/2009 em 22:24
fonte usuário

votos
0

Você deve entender o que (x > 5)realmente significa. Assumindo que xrepresenta um número, então é basicamente "classifica" todos os números maiores do que cinco. Assim, o código ficaria assim em uma linguagem com sintaxe python:

class Number(Object):

    # ... Number implementation code ... #

    def doSomething():
        self = 0
        return self

    def doSomethingElse():
        pass

class GreaterThan5(Number):
    def doSomething():
        print "I am " + self

    def doSomethingElse():
        print "I like turtles!"

Então nós poderia executar código como o seguinte:

>>> type(3)
<class Number>
>>> type(3+3)
<class GreaterThan5>
>>> 3.doSomething()
0
>>> (3 + 3).doSomething()
I am 6
>>> (7 - 3).doSomethingElse()
>>>

A conversão automática de tipo aqui é importante. Tanto quanto eu saiba, nenhuma das línguas hoje permitem que você mexer com números inteiros tanto.

No final, você pode fazer em seu código que seja. Enquanto as pessoas lendo isso pode entender imediatamente. Assim, a expedição polimórfica em inteiros ou qualquer coisa unordinary deve ter realmente bom raciocínio por trás dele.

Respondeu 28/01/2018 em 03:02
fonte usuário

votos
0

Concordo com Vance que o IF não é bom, porque aumenta a complexidade condicional e deve ser evitado possível.

Polimorfismo é uma solução totalmente viável a condição é usado para dar sentido e não para "evitar se".

Uma nota que não se encaixa com suas necessidades OOP mas a abordagem orientada a dados também tende a evitar a ramificação .

Respondeu 06/09/2017 em 10:28
fonte usuário

votos
0

Meus dois bits aqui do que eu entendo da abordagem Orientada a Objetos -

Primeiro, o que os objetos em um programa deve ser intuitivo. Ou seja, eu não deveria tentar criar uma classe 'Aritmética' para fornecer funções matemáticas. Isto é um abuso de OOD.

Segunda e esta é uma opinião muito forte da mina. Ele não deve ser chamado Object Oriented design, mas objetos e design de método orientado! Se os nomes dos métodos dos objetos são eles próprios não intuitivos objetos, em seguida, herdadas pode acabar reimplementar os métodos já disponíveis.

Objeto abordagem orientada, de acordo com a mim, não é um substituto para a abordagem processual. Pelo contrário, é principalmente por duas razões principais para os criadores da linguagem -

  1. Melhor capacidade de escopo de variáveis.

  2. Melhor capacidade de coleta de lixo, em vez de ter muitas variáveis ​​globais.

Respondeu 26/09/2009 em 14:19
fonte usuário

votos
0

Eu tenho acompanhado o caso anti conversa ultimamente e soa como retórica extrema / hiperbólica para mim. No entanto eu acho que há verdade nesta afirmação: muitas vezes a lógica de uma instrução if pode ser implementado de forma mais adequada através de polimorfismo. Eu acho que é bom manter isso em mente toda vez que você direita uma instrução if. Dito isto, acho que a declaração se ainda é uma estrutura lógica do núcleo, e não deve ser temido ou evitado como um princípio.

Respondeu 26/08/2009 em 23:01
fonte usuário

votos
0

Se-declarações são bastante núcleo de programação assim, em suma, você não pode sensatamente evitá-los.

No entanto, um objetivo-chave em OOP - na verdade, um dos "pilares" - é o encapsulamento. O velho "encapsular o que varia" regra ajuda a remover esses problemático se e casos de declarações em que você está tentando dar conta de cada opção no seu objeto. A melhor solução para lidar com ramos, casos especiais, etc. é usar algo como o padrão de design "Factory" (Abstract Factory ou Factory Method - dependendo das necessidades, é claro).

Por exemplo, em vez de ter seu cheque ciclo de código principal qual sistema operacional o seu uso com if seguida ramificar para criar janelas de GUI com diferentes opções para cada OS, o código principal seria criar um objeto a partir da fábrica, que usam o sistema operacional para determinar qual sistema operacional objeto concreto espec�ico para fazer. Ao fazer isso você está tomando as variações (e as cláusulas longo if-then-else) fora de seu ciclo de código principal e deixar a criança objetos lidar com isso - Então, da próxima vez que você precisa para fazer uma mudança, como apoiar um novo sistema operacional , você simplesmente adicionar uma nova classe a partir da interface de fábrica.

Respondeu 26/08/2009 em 22:41
fonte usuário

votos
0

Eu vou dizer a resposta é vagamente sim-ish. Especialmente quando a linguagem permite alguma programação funcional pesados ​​(ou seja, C #, F #, OCaml).

Um componente que contém 2 se declarações fortemente casais duas regras de negócios para quebrá-lo.

Tomar isso como uma regra muito geral do polegar, mas eu concordaria. Se você tem um monte de instruções IF, talvez você deve pensar em outra abordagem.

Respondeu 26/08/2009 em 22:40
fonte usuário

votos
0

Eu acho que aplicar esse argumento para a idéia de cada if é bastante extremo, mas alguns idiomas dar-lhe a capacidade de aplicar essa idéia em determinados cenários.

Aqui está um exemplo de implementação Python Eu escrevi no passado para uma de tamanho fixo deque (deque). Em vez de criar um método "remover" e ter if dentro dele para ver se a lista está cheia ou não, você acabou de criar dois métodos e reenviá-los para a função "remover", conforme necessário.

O exemplo a seguir lista apenas o método "remover", mas, obviamente, há "acrescentar" métodos e similares também.

class StaticDeque(collections.deque):

    def __init__(self, maxSize):

        collections.deque.__init__(self)
        self._maxSize = int(maxSize)
        self._setNotFull()

    def _setFull(self):

        self._full = True
        self.remove = self._full_remove

    def _setNotFull(self):

        self._full = False
        self.remove = self._not_full_remove

    def _not_full_remove(self,value):

        collections.deque.remove(self,value)

    def _full_remove(self,value):

        collections.deque.remove(self,value)
        if len(self) != self._maxSize and self._full:
            self._setNotFull()

Na maioria dos casos não é tão útil de uma idéia, mas às vezes pode ser útil.

Respondeu 26/08/2009 em 22:28
fonte usuário

votos
0

Certamente alguma forma de comparação deve ser feita independentemente do que você faz? No final ... se você pode evitar se declarações, mas você ficaria código de produzir que é idêntico ao código usando uma instrução if.

Alguém me corrija se estou errado, mas eu não consigo pensar em um momento onde você pode obter qualquer forma vitória fazendo isso.

Respondeu 26/08/2009 em 22:24
fonte usuário

votos
0

É bastante extremo. Fazendo o que você está sugerindo causaria um monte de duplicação de código desnecessário, a menos que toda a função era completamente diferente, com base em um único circundante se; e em caso afirmativo, de que se deveria ter sido do outro lado da invocação de método.

Se-declarações certamente têm o seu lugar no projeto objeto-orient.

Respondeu 26/08/2009 em 22:24
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more