Skip to content

Fabian-Martinez-Rincon/Orientacion-a-Objetos-2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

96 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

contributions welcome GitHub stars GitHub repo size in bytes


Que hacer ante cada bad smell:

  • Data Expose (Atributos que son publicos)
    • Refactoring: Encapsulate Field
    • Que hacer: Pasamos los atributos a privados y en los lugares en donde se usaban los atributos, se cambia por los metodos get y set.
  • Envidia de Atributos (Nos tenemos que acordar de aplicar el refactor anterior antes de este)
    • Refactoring: Move Method to Component
    • Que hacer: Mover el metodo a la clase que tiene los atributos que necesita.
  • Long Method (Casi siempre se corresponde al exceso de responsabilidades)
    • Refactoring: Extract Method
    • Que hacer: Movemos el codigo a un metodo de la misma clase con un nombre descriptivo
  • Reinventado la rueda: (Despues de hacer el extract method que contiene fors)
    • Refactoring: Remplazar el codigo por funcion de la libreria
    • Que hacer: Si tenemos algun for, buscar en los streams con cual se puede remplazar.

Tip

En la consulta me dijeron que no hace falta copiar y pegar el codigo, con explicar el paso a paso de los refactorings basta. Podes usar las reglas que se encuentran arriba.


Refactoring: Transformaciones de código que preservan el comportamiento

  • Preservar el comportamiento
  • (Hace lo que hacía antes) & (No hace lo que no hacía antes) *

1.1 Protocolo de Cliente

La clase Cliente tiene el siguiente protocolo. ¿Cómo puede mejorarlo?

/**
* Retorna el límite de crédito del cliente
*/
protected double lmtCrdt() {...
/**
* Retorna el monto facturado al cliente desde la fecha f1 a la fecha f2
*/
protected double mtFcE(LocalDate f1, LocalDate f2) {...
/**
* Retorna el monto cobrado al cliente desde la fecha f1 a la fecha f2
*/
protected double mtCbE(LocalDate f1, LocalDate f2) {...

El bad smell es nombre poco descriptivo ya que si en un futuro vienen nuevos desarrolladores a trabajar, no van a entender como funciona el código.

El refactoring a utilizar es rename method, sobre los metodos. Pero esto no termina aca, el refactoring termina recien cuando en todas las llamadas a estos metodos se cambie el nombre. En caso contrario, no se considera refactoring ya que tendremos errores al llamar un metodo que antes no existia.

Hacemos lo mismo con los parametros pero en este caso, solo hace falta modificarlos en el metodo, ya que la funcionalidad externa se abstrae del nombre de los parametros.


1.2 Participación en proyectos

Al revisar el siguiente diseño inicial (Figura 1), se decidió realizar un cambio para evitar lo que se consideraba un mal olor. El diseño modificado se muestra en la Figura 2. Indique qué tipo de cambio se realizó y si lo considera apropiado. Justifique su respuesta.

Diseño inicial:

image

La clase Persona tiene el mal olor de que no cumple con el principio de responsabilidad única. Se utiliza el refactoring de move method to component para mover el metodo participaEnProyecto a la clase Proyecto.

No se considera un refactoring ya que estas eliminando el metodo del objeto Persona esto no preserva el comportamiento en la clase.

Si queremos que de verdad sea un refactoring podemos tener a la clase Persona de la siguiente manera:

public class Persona {
    public String id;
    public boolean participaEnProyecto(Proyecto proyecto) {
        return proyecto.participa(this);
    }
}
public clase  Proyecto {
    private List<Persona> participantes;
    public boolean participa(Persona persona) {
        return participantes.contains(persona);
    }
}

De esta forma, la gente que trabaja con la clase, no se ve afectada por el cambio.


1.3 Cálculos

Analice el código que se muestra a continuación. Indique qué defectos encuentra y cómo pueden corregirse.

public void imprimirValores() {
    int totalEdades = 0;
    double promedioEdades = 0;
    double totalSalarios = 0;
    for (Empleado empleado : personal) {
        totalEdades = totalEdades + empleado.getEdad();
        totalSalarios = totalSalarios + empleado.getSalario();
    }
    promedioEdades = totalEdades / personal.size();
    String message = String.format("El promedio de las edades es %s y el total de salarios es %s", promedioEdades, totalSalarios);
    System.out.println(message);
}

El mal olor es Long Method ya que el metodo esta teniendo muchas responsabilidades como "Calcular el promedio de edades" y "Calcular el total de salarios".

Para mejorar el codigo aplicamos extract method y creamos dos metodos calcularPromedioEdades y calcularTotalSalarios.

public double calcularPromedioEdades() {
    int totalEdades = 0;
    for (Empleado empleado : personal) {
        totalEdades = totalEdades + empleado.getEdad();
    }
    return totalEdades / personal.size();
}

public double calcularTotalSalarios() {
    double totalSalarios = 0;
    for (Empleado empleado : personal) {
        totalSalarios = totalSalarios + empleado.getSalario();
    }
    return totalSalarios;
}

public void imprimirValores() {
    System.out.println(String.format(
        "El promedio de las edades es %s y el total de salarios es %s", 
        this.calcularPromedioEdades(), this.calcularTotalSalarios())
    );
}

Otro bads mell Reinventando la rueda es que se puede reemplazar el for por un stream.

Warning

Tiene que cumplir con el mismo comportamiento que antes.

En este caso al dividir por cero, el codigo lanza una excepcion que debe seguir teniendo despues del refactoring.

Esto godEsto es morir
public double calcularPromedioEdades(){ 
    return personal.stream()
        .mapToDouble(empleado -> empleado.getEdad())
        .sum()/personal.size(); 
}
public double calcularPromedioEdades(){ 
    return personal.stream()
        .mapToDouble(empleado -> empleado.getEdad())
        .average()
        .orElse(0); 
}

Ejercicio 2

Para cada una de las siguientes situaciones, realice en forma iterativa los siguientes pasos:

  • (i) indique el mal olor,
  • (ii) indique el refactoring que lo corrige,
  • (iii) aplique el refactoring, mostrando el resultado final (código y/o diseño según corresponda).

Si vuelve a encontrar un mal olor, retorne al paso (i).

2.1 Empleados

public class EmpleadoTemporario {
    public String nombre;
    public String apellido;
    public double sueldoBasico = 0;
    public double horasTrabajadas = 0;
    public int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.horasTrabajadas * 500) +
        (this.cantidadHijos * 1000) - (this.sueldoBasico * 0.13);
    }
}
public class EmpleadoPlanta {
    public String nombre;
    public String apellido;
    public double sueldoBasico = 0;
    public int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.cantidadHijos * 2000) -
        (this.sueldoBasico * 0.13);
    }
}
public class EmpleadoPasante {
    public String nombre;
    public String apellido;
    public double sueldoBasico = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico - (this.sueldoBasico * 0.13);
    }
}

Aca tenemos el bad smell de Data Expose y Codigo Duplicado.

Para solucionar el bad smell de Data Expose aplicamos el refactoring Encapsulate Field, pasamos los atributos publicos a privados, y en donde se usaban los atributos, se cambia por los metodos get y set.

public class EmpleadoTemporario {
    private String nombre;
    private String apellido;
    private double sueldoBasico = 0;
    private double horasTrabajadas = 0;
    private int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.horasTrabajadas * 500) +
        (this.cantidadHijos * 1000) - (this.sueldoBasico * 0.13);
    }
}
public class EmpleadoPlanta {
    private String nombre;
    private String apellido;
    private double sueldoBasico = 0;
    private int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.cantidadHijos * 2000) -
        (this.sueldoBasico * 0.13);
    }
}
public class EmpleadoPasante {
    private String nombre;
    private String apellido;
    private double sueldoBasico = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico - (this.sueldoBasico * 0.13);
    }
}

Continuamos con el bad smell de codigo duplicado. Para solucionarlo hacemos un refactoring Extract Class (aca tengo dudas del nombre) con los atributos y metodos en comun.

public class Empleado {
    private String nombre;
    private String apellido;
    private double sueldoBasico = 0;
    // ......
    public abstract double sueldo();
}

public class EmpleadoTemporario extends Empleado {
    private double horasTrabajadas = 0;
    private int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.horasTrabajadas * 500) +
        (this.cantidadHijos * 1000) - (this.sueldoBasico * 0.13);
    }
}

public class EmpleadoPlanta extends Empleado {
    private int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.cantidadHijos * 2000) -
        (this.sueldoBasico * 0.13);
    }
}

public class EmpleadoPasante extends Empleado {
    // ......
    public double sueldo() {
        return this.sueldoBasico - (this.sueldoBasico * 0.13);
    }
}

Seguimos con el bad smell Codigo Duplicado en la logica del calculo del sueldo basico. Para solucionarlo hacemos el refactoring Extract Method y despues aplicamos el refactoring Pull Up Method para que el metodo calcularBasico se encuentre en la clase padre.

public class Empleado {
    private String nombre;
    private String apellido;
    private double sueldoBasico = 0;
    // ......
    public double calcularBasico() {
        return this.sueldoBasico * 0.13;
    }
    public abstract double sueldo();
}

public class EmpleadoTemporario extends Empleado {
    private double horasTrabajadas = 0;
    private int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.horasTrabajadas * 500) +
        (this.cantidadHijos * 1000) - this.calcularBasico();
    }
}

public class EmpleadoPlanta extends Empleado {
    private int cantidadHijos = 0;
    // ......
    public double sueldo() {
        return this.sueldoBasico + (this.cantidadHijos * 2000) -
        this.calcularBasico();
    }
}

public class EmpleadoPasante extends Empleado {
    // ......
    public double sueldo() {
        return this.sueldoBasico - this.calcularBasico();
    }
}

2.2 Juego

public class Juego {
    // ......
    public void incrementar(Jugador j) {
        j.puntuacion = j.puntuacion + 100;
    }
    public void decrementar(Jugador j) {
        j.puntuacion = j.puntuacion - 50;
    }
}
public class Jugador {
    public String nombre;
    public String apellido;
    public int puntuacion = 0;
}

De primeras tenemos el bad smell de Data Expose y lo tratamos como siempre, cambiamos la visibilidad de public por private y remplazamos todas las llamadas por los metodos get y set.

public class Juego {
    // ......
    public void incrementar(Jugador j) {
        j.setPuntuacion(j.getPuntuacion() + 100);
    }
    public void decrementar(Jugador j) {
        j.setPuntuacion(j.getPuntuacion() - 50);
    }
}
public class Jugador {
    private String nombre;
    private String apellido;
    private int puntuacion = 0;

    public int getPuntuacion() {
        return puntuacion;
    }

    public void setPuntuacion(int puntuacion) {
        this.puntuacion = puntuacion;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getApellido() {
        return apellido;
    }

    public void setApellido(String apellido) {
        this.apellido = apellido;
    }
}

El bad smell que tenemos ahora es Envidia de atributos, lo que hacemos en este caso es move method to component y delegamos la responsabilidad de incrementar y decrementar la puntuacion al objeto Jugador.

public class Juego {
    public void incrementar(Jugador j) {
        j.incrementarPuntuacion(100);
    }
    public void decrementar(Jugador j) {
        j.decrementarPuntuacion(50);
    }
}
public class Jugador {
    private String nombre;
    private String apellido;
    private int puntuacion = 0;

    public void incrementarPuntuacion(int puntos) {
        this.puntuacion += puntos;
    }

    public void decrementarPuntuacion(int puntos) {
        this.puntuacion -= puntos;
    }
}

image

/*
* Retorna los últimos N posts que no pertenecen al usuario user
*/
public List<Post> ultimosPosts(Usuario user, int cantidad) {
    List<Post> postsOtrosUsuarios = new ArrayList<Post>();
    for (Post post : this.posts) {
        if (!post.getUsuario().equals(user)) {
            postsOtrosUsuarios.add(post);
        }
    }
    // ordena los posts por fecha
    for (int i = 0; i < postsOtrosUsuarios.size(); i++) {
        int masNuevo = i;
        for(int j= i +1; j < postsOtrosUsuarios.size(); j++) {
            if (postsOtrosUsuarios.get(j).getFecha().isAfter(
                postsOtrosUsuarios.get(masNuevo).getFecha())) {
                masNuevo = j;
            }
        }
        Post unPost = postsOtrosUsuarios.set(i,postsOtrosUsuarios.get(masNuevo));
        postsOtrosUsuarios.set(masNuevo, unPost);
    }
    
    List<Post> ultimosPosts = new ArrayList<Post>();
    int index = 0;
    Iterator<Post> postIterator = postsOtrosUsuarios.iterator();
    while (postIterator.hasNext() && index < cantidad) {
        ultimosPosts.add(postIterator.next());
    }
    return ultimosPosts;
}

En este caso tenemos el bad smell de Long Method y Reinventando la rueda. Hacemos el refactoring Extract Method y despues el de Remplazar el codigo por funcion de la libreria.

public List<Examen> filtrarYOrdenar(){
    return posts.stream()
        .filter(alumno->alumno.getNombre().startsWith(x))
        .sorted((p1, p2) -> 
            p1.getFecha().compareTo(p2.getFecha()))
        .collect(Collectors.toList());
}
/*
* Retorna los últimos N posts que no pertenecen al usuario user
*/
public List<Post> ultimosPosts(Usuario user, int cantidad) {
    List<Post> postsOtrosUsuarios = filtrarYOrdenar();
    
    List<Post> ultimosPosts = new ArrayList<Post>();
    int index = 0;
    Iterator<Post> postIterator = postsOtrosUsuarios.iterator();
    while (postIterator.hasNext() && index < cantidad) {
        ultimosPosts.add(postIterator.next());
    }
    return ultimosPosts;
}

Aca tenemos el bad smell de Codigo Reduntante y el refactoring es Remover codigo reduntante.

public List<Post> ultimosPosts(Usuario user, int cantidad) {
    return filtrarYOrdenar();
}

Tenemos el mal olor de marametro sin utilizar y el refactoring es Remover parametro no utilizado. Esto no queda aca, sino que tambien en todos los lugar en donde se llama a este metodo, vamos a tener que remover ese parametro. Sigue cumpliendo con el principio de refactoring ya que no estamos modificando el comportamiento en asboluto.

public List<Post> ultimosPosts(Usuario user, int cantidad) {
    return filtrarYOrdenar();
}

2.4 Carrito de compras

image

public class Producto {
    private String nombre;
    private double precio;
    public double getPrecio() {
        return this.precio;
    }
}
public class ItemCarrito {
    private Producto producto;
    private int cantidad;
    public Producto getProducto() {
        return this.producto;
    }
    public int getCantidad() {
        return this.cantidad;
    }
}
public class Carrito {
    private List<ItemCarrito> items;
    public double total() {
        return this.items.stream().mapToDouble(item ->
        item.getProducto().getPrecio() * item.getCantidad()).sum();
    }
}

Ejercicio 6: Antlr lab

Con cada uno de los siguientes ejemplos,

  • 1) Considere que en el lenguaje dado por la cátedra el llamado a una función o método retorna el valor generado por la evaluacion de la última sentencia (stat, en la gramática)
  • 2) Determine si hay un code smell y cual es.
  • 3) Evalue el código en antlr lab usando las especificaciones del lexer y el parser
  • 4) Estudie el árbol generado por antlr lab
  • 5) Escriba un pseudocódigo que permita detectar el code smell en el árbol
  • Pagina para ver los diagramas

Configuración

Lexer

// DELETE THIS CONTENT IF YOU PUT COMBINED GRAMMAR IN Parser TAB
lexer grammar ExprLexer;
AND : 'and' ;
OR : 'or' ;
NOT : 'not' ;
EQ : '=' ;
COMMA : ',' ;
SEMI : ';' ;
LPAREN : '(' ;
RPAREN : ')' ;
LCURLY : '{' ;
RCURLY : '}' ;
SUM : '+' ;
SUB : '-' ;
MUL : '*' ;
DIV : '/' ;
POW : '^' ;
DOT : '.' ;
COLON : ':' ;
ASK : '?' ;
INT : [0-9]+ ;
ID: [a-zA-Z_][a-zA-Z_0-9]* ;
WS: [ \t\n\r\f]+ -> skip ;

Parser

parser grammar ExprParser;
options { tokenVocab=ExprLexer; }
program
: stat EOF
| def EOF
;
stat: ID '=' expr ';'
| ID DOT ID '=' expr ';'
| expr ';'
;
def : ID '(' ID (',' ID)* ')' '{' stat* '}' ;
expr: ID   //EXPR 1
| INT      //EXPR 2
| func     //EXPR 3
| ID DOT ID //empleado.sueldo // EXPR 4
| ID DOT func //empleado.calcularSueldo() // EXPR 5
| 'not' expr // EXPR 6
| expr 'and' expr // EXPR 7
| expr 'or' expr // EXPR 8
| expr (MUL | DIV) expr // EXPR 9
| expr (SUM | SUB) expr // EXPR 10
| expr POW expr // EXPR 11
| expr '?' expr ':' expr // EXPR 12
| expr '?' expr // EXPR 13
;
func : ID '(' expr (',' expr)* ')'
| ID '(' ')'
;

Tabla de Code Smell con su correspondiente psudocodigo

Tip

Pseudo deriva del griego, de seudo, que puede traducirse como falso. Código, por su parte, emana del latín. En concreto, de “codices, codex” que se empleaban para referirse a los documentos o libros donde los romanos tenían escritas todas y cada una de sus leyes.

6.1

f(x,y) {
    a = 4
    a = 3 + y;
    x * x + y * x; 
}

image

Pseudocodigo

El Bad Smell 1 encontrado es variable pisada y el pseudocodigo para detectarlo es el siguiente:

  • Recorro el arbol hasta encontrar el primer stat con ID1 que representa la asignación, me quedo con el primer hijo y lo guardo en una variable auxiliar.
  • Vuelvo a recorrer el arbol y si encuento otro stat con ID1 (asignación) y el hijo es igual a la variable auxiliar y en el medio no se encuentra como hija de ningun nodo EXPR, significa que es un valor pisado.

El Bad Smell 2 encontrado es variable no utilizada y el pseudocodigo para detectarlo es el siguiente:

  • Recorro el arbol hasta encontrar el primer stat con ID1 que representa la asignación, me quedo con el primer hijo y lo guardo en una variable/lista auxiliar.
  • Vuelvon a recorrer el arbol y si no es hijo de algun nodo EXPR, significa que no se utiliza.

6.2

f(x, y, z) {
    a = 3 + y;
    x * x + y * x;  
}

image

Pseudocodigo

Tenemos dos Bad Smell un parametro sin utilizar y una variable que no se utiliza

  • Recorro el arbol hasta encontrar el nodo con expresión def y me guardo en una lista, los valores de los ID que se encuentran entre parentesis.
  • Volvemos a recorrer el arbol buscando que los elementos de la lista no sean hijos de ningun nodo EXPR. En caso de que no sea hijo de ningun nodo EXPR, significa que el parametro no se utiliza.

6.3

f(x,y) {
    a = 4;
    x + a;
}

image

Pseudocodigo

Tenemos dos Bad Smell un parametro sin utilizar

  • Recorro el arbol hasta encontrar el nodo con expresión def y me guardo en una lista, los valores de los ID que se encuentran entre parentesis.
  • Volvemos a recorrer el arbol buscando que los elementos de la lista no sean hijos de ningun nodo EXPR. En caso de que no sea hijo de ningun nodo EXPR, significa que el parametro no se utiliza.

6.4

f(x) {
    a = 4;
    a = 5;
}

image

El Bad Smell encontrado es variable pisada y el pseudocodigo para detectarlo es el siguiente:

  • Recorro el arbol hasta encontrar el primer stat con ID1 que representa la asignación, me quedo con el primer hijo y lo guardo en una variable auxiliar.
  • Vuelvo a recorrer el arbol y si encuento otro stat con ID1 (asignación) y el hijo es igual a la variable auxiliar y en el medio no se encuentra como hija de ningun nodo EXPR, significa que es un valor pisado.

6.5

f(x) {
    a = x ? 3 : 3;
}

image

Pseudocodigo

El Bad Smell encontrado es condicional redundante y el pseudocodigo para detectarlo es el siguiente:

Recorro el arbol hasta encontrar un nodo EXPR con la siguiente estructura EXPR ? EXPR : EXPR y si los dos ultimos hijos tienen el mismo valor, significa que el condicional no es necerario que se encuentre.


6.6

f(y) {
    a = g.x() + g.x() + g.x();
}

image

Pseudocodigo

Tenemos dos Bad Smell un parametro sin utilizar

  • Recorro el arbol hasta encontrar el nodo con expresión def y me guardo en una lista, los valores de los ID que se encuentran entre parentesis.
  • Volvemos a recorrer el arbol buscando que los elementos de la lista no sean hijos de ningun nodo EXPR. En caso de que no sea hijo de ningun nodo EXPR, significa que el parametro no se utiliza.

6.7

f(y) {
    a = not not y;
}

image

Pseudocodigo

El Bad Smell es Logica Reduntante y el pseudocodigo para detectarlo es el siguiente:

  • Recorro el arbol hasta encontrar un nodo EXPR que tenga como hijo un not y si su nodo hermano EXPR tiene como hijo otro not, significa que es logica redundante.

6.8

f(y, z) {
    z + 12;
}

image

Pseudocodigo

Tenemos dos Bad Smell un parametro sin utilizar

  • Recorro el arbol hasta encontrar el nodo con expresión def y me guardo en una lista, los valores de los ID que se encuentran entre parentesis.
  • Volvemos a recorrer el arbol buscando que los elementos de la lista no sean hijos de ningun nodo EXPR. En caso de que no sea hijo de ningun nodo EXPR, significa que el parametro no se utiliza.

6.9

elegirSueldo(empleado) {
    clase = empleado.class;
    clase.equals(pasante) ? empleado.setSueldo(20000);
    clase.equals(planta) ? empleado.setSueldo(50000);
}

image

El Bad smell es Switch statement ya que estoy utilizando clase de empleado para determinar el sueldo a setear. Esto no es escalable ya que si en un futuro quiero seguir agregando tipos de empleados, tengo que modificar el metodo.

El pseudocodigo para detectar este bad smell es el siguiente:

  • Busco el nodo def y me guardo en una variable auxiliar los valores pasados por parametro, en este caso es empleado
  • Vuelvo a recorrer el arbol y busco un nodo con STAT:1 que representa la asignación y si tiene como hijo un nodo EXPR que contiene el valor de mi variable auxiliar y la siguiente estructura aux.class. Me quedo con el primer hijo que en este caso es clase
  • Una vez que tengo guardado clase en una variable auxiliar, vuelvo a recorrer el arbol hasta encontrar un nodo EXPR con la siguiente estructura auxiliar . equals ( EXPR ).
  • Si encuentro un nodo con esta estructura, significa que tengo un Switch statement.

6.10

agregarOnceNumeros(lista) {
    lista.agregar(1);
    lista.agregar(2);
    lista.agregar(3);
    lista.agregar(4);
    lista.agregar(5);
    lista.agregar(6);
    lista.agregar(7);
    lista.agregar(8);
    lista.agregar(9);
    lista.agregar(10);
    lista.agregar(11);
}

image

El Bad Smell es Reinventado la rueda ya que tengo operaciones que repiten un patron en secuencia, por lo que se podrian remplazar por un for. Como por ejemplo

agregarOnceNumeros(lista) {
    for (int i = 1; i <= 11; i++) {
        lista.agregar(i);
    }
}

Pseudocodigo

Para encontrar el Bad Smell hacemos lo siguiente:

  • Recorro el arbol quedandome con la estructura completa de los nodos stat:3
  • Sobre la lista que guarde, elimino todas las estructuras duplicadas
  • Si el resultado me queda una secuencia de numeros, significa que puedo remplazarlo por un for.

El resultado quedaria algo asi

[1,2,3,4,5,6,7,8,9,10,11]


6.11

numeroTelefonoCompleto(telefono, numero) { 
    numero = telefono.codigoArea + telefono.prefijo + telefono.numero;
}

image

Pseudocodigo

El Bad Smell es Envidia de Atributos

  • Recorro el arbol hasta encontrar el nodo con expresión def y me guardo en una lista, los valores de los ID que se encuentran entre parentesis.
  • Volvemos a recorrer el arbol buscando que los elementos de la lista no sean hijos de un nodo EXPR:4 con la siguiente estructura telefono . atributoX
  • En caso de encontrar estos nodos, estamos en presencia de un Envidia de Atributos.

6.11

f(x,y) { x = true , y = 2
    x or not x ? y + 1;  
    x and x ? y - 1;
    x ? x ? y - 1;
}

image

Resultado con if

ejemplo
f(x, y) {//x = true, y = 2;
    
    // Primera Condición
    if (x || !x) {
        y = y + 1;
    }
    
    // Segunda Condición
    if (x && x) {
        y = y - 1;
    }
    
    // Tercera Condición
    if (x) {
        if (x) {
            y = y - 1;
        }
    }
}

El bad smell es codigo reduntante, el codigo sin redundacia quedaria asi

f(x, y) {//x = true, y = 2;
    if (x) {
        y = y - 1;
    }
}

Pseudocodigo

Primer Stat 3

  • Recorro el arbol hasta encontrar un nodo EXPR:8 y me guardo el hijo izquierdo en una variable auxiliar.
  • Si el hijo mas derecho de mi nodo EXPR:8, tiene el hijo izquierdo un not y el hijo derecho es igual a la variable auxiliar, significa que es logica redundante.

Segundo Stat 3

  • Recorro el arbol hasta encontrar un nodo EXPR:7 y me guardo la estructura del hijo izquierdo en una variable auxiliar.
  • Si el hijo mas derecho de mi nodo EXPR:7, tiene la misma estructura que la variable auxiliar, significa que es logica redundante.

Tercer Stat 3

  • Recorro el arbol hasta encontrar un nodo EXPR:13 y me guardo la estructura del hijo izquierdo en una variable auxiliar.
  • Si el hijo mas derecho de mi nodo EXPR:13, tiene la misma estructura que la variable auxiliar, significa que es logica redundante.

6.12

"¡REZÁ MALENA... REZÁ!"

LA ULTIMA LINEA SE RETORNA SI EN LA ULTIMA TENES UNA ASIGNACION, SE RETORNA EL VALOR DE LA COMPARACION

// La funcionalidad es que siempre retorna TRUE
f(x) {//x = 4  -> True
    x = x;
}

image

  • Paso 1) Recorro el arbol el arbol hasta encontrar el nodo con stat:1, me guardo el valor en una variable auxiliar
  • Paso 2)

6.13

f(x,y) { // x = TRUE -> f  // y = 5
    x ? y - 1; // y = 4
    not x ? y - 2;  // if (not x) return y-2
}

ESTO TIENE QUE RETORNAR LA ULTIMA | Si el valor de X es falso, no retorno NADA

image

El bad smell es que si x es falso, no estaria retornando ningun valor. Ya que el return se encuentra dentro del if

Busco el nodo expr:13 de mi ultimo stat:3, y busco sobre sus nodos hijos, en caso de que no tenga el valor : que me indica que es un else, significa que no estoy retornando nada para una situación en especifico.


6.14

f(a,b,c,d,e,f,g,h,i,j,k) {
    a+b+c+d+e+f+g+h+i+j+k;
}

image

El bad smell es Long Parameter List y el pseudocodigo para detectarlo es el siguiente:

Recorremos el arbol buscando el nodo def:1 y nos quedamos con todos los elementos de la lista, y a esa lista le hacemos un .size() y si es mayor a 3/4 es un indicador Long Parameter List.


6.15

someOperation(x,y,z) {
    other.someOperation(x,y,z);
}
Persona {
    Contador contador;

    calcularSueldo(sueldoBruto, obraSocial, jubilacion) {
        contador.calcularSueldoNeto(sueldoBruto, obraSocial, jubilacion);
    }
}

image

El bad smell es Middle Man y el pseudocodigo para detectarlo es el siguiente:

  • Recorremos el arbol hasta encontrar el nodo def:1, nos guardamos los valores que estan entre parentesis en una lista auxiliar y el valor del hijo izquierdo en otro variable llamada nombreFuncion
  • Volvemos a recorrer el arbol buscando que tenga solo un nodo STAT:3
  • El Hijo izquierdo tiene que ser un nodo EXPR:5 y me quedo con su hijo derecho func:1
  • Si el hijo izquierdo de func:1 es igual a nombreFuncion y el resto de los hijos que estan entre parentesis es igual a la lista auxiliar que me guarde significa que es un Middle Man.

About

☕ Patrones de Diseño, Refactoring y Frameworks

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages