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
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