Como não utilizar IF ou SWITCH?

Pessoal,

Gostaria de saber como posso fazer uma implementação simples (um exemplo) não utilizando IF ou SWITCH. Alguém pode me ajudar?

[]s
Thiago

Olá, seja bem-vindo ao GUJ!
Quando tiver um tempo, leia esse artigo que vai te orientar a como usar alguns recursos do forum.

Esse assunto é muito estressado no livro refatoração, do Martin/Fowler. O princípio básico é substituir ifs e switchs por polimorfismo.

Vou mostrar com um exemplo com o padrão Strategy. Considere a classe:

[code]
public class TextFinder {
private static final int BEGINS = 0;
private static final int ENDS = 1;
private static final int CONTAINS = 2;
private static final int EQUALS = 3;
private static final int REGEX = 4;

public static boolean findText(String text, String expected, int criteria) {
   swtich (criteria) {
      case BEGINS:
         return text.startsWith(expected);
      case ENDS:
         return text.endsWith(expected);
      case CONTAINS:
         return text.contains(expected);
      case EQUALS:
         return text.equals(expected);
      case REGEX:
         Matcher matcher = Pattern.compile(expected).matcher(text);
         return matcher.find();
   }
}

}[/code]

Para usar esse método, o usuário faz algo como:

boolean containsGodoy = TextFinder.findText("Vinícius Godoy de Mendonça", "Godoy", TextFinder.CONTAINS);

Onde está o strategy nesse código? Bom, o criteria pode ser transformado num strategy. Podemos fazer isso de maneira simples, através de um enum:

[code]
public enum SearchCriteria {
BEGINS {
@Override public boolean doVerify(String text, String expected) {
return text.substring(0, expected.length()).equals(expected);
}
},
ENDS {
@Override public boolean doVerify(String text, String expected) {
return text.endsWith(expected);
}
},
CONTAINS {
@Override public boolean doVerify(String text, String expected) {
return text.contains(expected);
}
},
EQUALS {
@Override public boolean doVerify(String text, String expected) {
return text.equals(expected);
}
},
REGEX {
@Override public boolean doVerify(String text, String expected) {
Matcher matcher = Pattern.compile(expected).matcher(text);
return matcher.find();
}
};

 public final boolean verify(String text, String expected) {
     if (text == null)
         throw new IllegalArgumentException("Text cannot be null!");
     
     if (expected == null)
         throw new IllegalArgumentException("Expected text cannot be null!");
     
     return doVerify(text, expected);
 }
 
 public abstract boolean doVerify(String text, String expected);

}[/code]

Agora, aquele nosso código com o switch seria trocado por:

public class TextFinder { public static boolean findText(String text, String expected, SearchCriteria criteria) { return criteria.verify(text, expected); } }

Para usar o novo método, o usuário fará:

boolean containsGodoy = TextFinder.findText("Vinícius Godoy de Mendonça", "Godoy", SearchCriteria.CONTAINS); 

Note que o switch foi completamente eliminado.

Outra vantagem é que fossemos adicionar outro método a esse strategy (por exemplo, NOT_CONTAINS), teríamos que modificar apenas o enum, e não localizar no código todos os pontos onde o switch é utilizado.

Finalmente, você poderia ter mais de um método abstrato em cada item do strategy. Não é esse caso, mas se você tivesse um enum com algoritmos de criptografia, você poderia ter o encode e o decode. A grande vantagem é que, quando alguém fosse implementar um novo algoritmo, teria um “template” pronto de quais métodos ele deve fornecer. Assim, não há risco de alguém implementar um encode() sem pelo notar a necessidade de implementar um decode().

Olá …

Fiquei com uma dúvida … nesse não há os ConcreteStrategy??

Eles não são necessários para que se caracterize o padrão??

Grato

Cada item do enum é um ConcreteStrategy. Nesse caso, as inner classes anônimas que implementam o comportamento do Begin, Contains, Regex, Ends e Equals.

O AbstractStrategy é dado pela própria classe do enum, que tem um método virtual. No lugar desse método virtual, o Enum poderia implementar uma interface SearchStrategy, com esse método, o que daria na mesma (embora ficasse um pouco mais flexível).

Só não fiz isso pq não tinha porque complicar o exemplo. A idéia aqui era mostrar como eliminar o switch, não tanto dar uma aula sobre o padrão e seus detalhes.

Ok

Agradeço a atenção