J'ai lu beaucoup de sujets sur la refactorisation de code et l'évitement des instructions if else. En fait, j'ai une classe où j'utilise beaucoup de conditions if - else.
Plus de détails: j'utilise le pull parser et sur chaque ligne de ma réponse soap, je vais vérifier s'il y a une balise qui m'intéresse, sinon, vérifier une autre balise etc:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice")){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialOffice += xpp.getText();
}
}
else if (soapResponse.equals("EditorialBoard")){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialBoard += xpp.getText();
}
}
else if (soapResponse.equals("AdvisoryBoard")){
eventType = xpp.next();
if (xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
}
}
eventType = xpp.next();
}
Maintenant, je voudrais utiliser autre chose, au lieu de ces conditions if else, mais je ne sais pas quoi.
Pouvez-vous me donner un exemple ou une bonne page de tutoriel?
Merci.
Dans ce cas particulier, étant donné que le code est essentiellement identique pour les 3 cas, à l'exception de la chaîne ajoutée, j'aurais une entrée de mappage pour chacune des chaînes en cours de construction:
Map<String,String> map = new HashMap<String,String>();
map.put("EditorialOffice","");
map.put("EditorialBoard","");
map.put("AdvisoryBoard","");
// could make constants for above Strings, or even an enum
puis modifiez votre code comme suit
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
String current = map.get(soapResponse);
if (current != null && xpp.getText()!=null) {
map.put( soapResponse, current += xpp.getText());
}
eventType = xpp.next();
}
Non "si ... alors ... sinon". Pas même la complexité supplémentaire de plusieurs classes pour les modèles de stratégie, etc. Les cartes sont votre ami. La stratégie est excellente dans certaines situations, mais celle-ci est assez simple pour être résolue sans.
Essayez de regarder le modèle de stratégie.
Petit exemple:
// Interface
public interface IResponseHandler {
public void handleResponse(XmlPullParser xxp);
}
// Concrete class for EditorialOffice response
private class EditorialOfficeHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Do something to handle Editorial Office response
}
}
// Concrete class for EditorialBoard response
private class EditorialBoardHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Do something to handle Editorial Board response
}
}
À un endroit, vous devez créer les gestionnaires:
Map<String, IResponseHandler> strategyHandlers = new HashMap<String,IResponseHandler>();
strategyHandlers.put("EditorialOffice", new EditorialOfficeHandler());
strategyHandlers.put("EditorialBoard", new EditorialBoardHandler());
Où avez-vous reçu la réponse:
IResponseHandler responseHandler = strategyHandlers.get(soapResponse);
responseHandler.handleResponse(xxp);
Dans Java 7 vous pouvez COMMUTER sur les chaînes. Vous pouvez l'utiliser si vous pouvez l'utiliser ;-)
Outre le commentaire de zzzzzzz (etc.) ... gardez à l'esprit que vous utilisez XmlPullParser qui vous fait écrire du code laid comme celui que vous avez. Vous pouvez enregistrer des rappels qui diviseraient votre code et le rendraient "meilleur", mais si possible, utilisez simplement la bibliothèque SimpleXML ou similaire.
En outre, vous pouvez refactoriser votre code pour le rendre plus lisible et moins verbeux. Par exemple, pourquoi appelez-vous xpp.next()
à l'intérieur de chaque instruction if? Pourquoi ne pas l'appeler une seule fois à l'extérieur:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice") && xpp.getText()!=null){
editorialOffice += xpp.getText();
}
else if (soapResponse.equals("EditorialBoard") && xpp.getText()!=null){
editorialBoard += xpp.getText();
}
else if (soapResponse.equals("AdvisoryBoard") && xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
}
eventType = xpp.next();
Vous n'avez pas mentionné si vous pouvez ou utilisez Java 7. À partir de là Java version, vous pouvez utiliser Chaînes dans les instructions switch =.
À part cela, encapsuler la logique de chaque cas est une bonne idée, par exemple:
Map<String, Department> strategyMap = new HashMap<String, Department>();
strategyMap.put("EditorialOffice", new EditorialOfficeDepartment());
strategyMap.put("EditorialBoard", new EditorialBoardDepartment());
strategyMap.put("AdvisoryBoard", new AdvisoryBoardDepartment());
Ensuite, vous pouvez simplement sélectionner la bonne stratégie dans la carte et l'utiliser:
String soapResponse = xpp.getName();
Department department = strategyMap.get(soapResponse);
department.addText(xpp.getText());
Department
est bien sûr dans l'interface ...
vaste question qui est celle-ci et il n'y a pas de vraie réponse. (et je n'utilise pas de savon très souvent)
voici quelques idées basées sur votre code:
vous pouvez d'abord regrouper le code en double
if (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard")){
Une autre bonne chose que vous pouvez faire est de jouer avec des commutateurs comme:
switch(soapResponse){
case "EditorialOffice":
case "EditorialBoard":
case "AdvisoryBoard":
eventType = xpp.next();
if (xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
break;
Vous devriez également envisager de diviser votre test en petites fonctions:
public bool interestingTag(string s){
return (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard"));
}
public processData(xpp){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialBoard += xpp.getText();
}
....}
Pour que vous puissiez simplement traiter toutes vos réponses dans une boucle while et que vous soyez super long si autre devient une fonction de 5 à 10 lignes
Mais comme je l'ai dit, il y a tellement de bonnes façons de faire la même chose
Vous pouvez créer une interface ResponseHandler avec trois implémentations, une pour chaque branche de votre construction if/else.
Ensuite, ayez soit une carte mappant les différentes soapResponses à un gestionnaire, soit une liste avec tous les gestionnaires s'il peut gérer cette soapResponse.
Vous devriez également pouvoir déplacer une partie du code passe-partout vers une implémentation commune, éventuellement abstraite, de la classe du gestionnaire de réponses.
Comme souvent, il en existe de nombreuses variantes. En utilisant la duplication de code, il suffit en fait d'une seule implémentation:
class ResponseHandler{
String stringToBuild = "" // or what ever you need
private final String matchString
ResponseHandler(String aMatchString){
matchString = aMatchString
}
void handle(XppsType xpp){
if (xpp.getName().toString().equals(matchString){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialOffice += xpp.getText();
}
}
}
}
Votre code devient
List<ResponseHandler> handlers = Arrays.asList(
new ResponseHandler("EditorialOffice"),
new ResponseHandler("EditorialBoard"),
new ResponseHandler("AdvisoryBoard"));
if(eventType == XmlPullParser.START_TAG) {
for(ResponseHandler h : handlers)
h.handle(xpp);
}
Vous pouvez définir une énumération comme suit:
public enum SoapResponseType {
EditorialOffice(1, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
},
EditorialBoard(2, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
},
AdvisoryBoard(3, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
};
public static SoapResponseType nameOf(String name) {
for (SoapResponseType type : values()) {
if (type.getName().equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
public void handle(XmlPullParser xpp) {
return null;
}
}
Utilisez l'énumération ci-dessus comme ceci:
SoapResponseType type = SoapResponseType.nameOf("input string");
if (type != null) {
type.handle(xpp);
}
C'est du code propre, n'est-ce pas!