Showing posts with label Buenas Prácticas - Programación. Show all posts
Showing posts with label Buenas Prácticas - Programación. Show all posts

La palabra reservada final en Java

Se emplea final para impedir cambios para elementos de variables, métodos y/o clases. Se puede querer evitar cambios debido a nuestro diseño o la búsqueda de eficiencia y seguridad. Vamos a ver tres maneras de usar la palabra reservada final en Java

1 - Variables

Una variable con la palabra final delante, es una variable cuyo valor no puede cambiar después de que haya sido inicializada. Por ello, esta es la manera de definir constantes en java. Por ejemplo:

       public static final String ERROR_GENERICO = "Error";

El valor de la variable ERROR_GENERICO no va a cambiar una vez que fue inicializada.

Por lo general, en la declaración de variables, la palabra reservada final viene acompañada de static. Además, la mayoría de los programadores declaran a las variables todas en mayúsculas por convención. De esta manera, es fácil reconocer el uso de "variables finales" en los programas.

Ver más información sobre la palabra reservada static.

2 - Métodos

Un método con la palabra final delante, es un método que no puede ser sobreescrito por una subclase. Es decir, si la clase en donde está definido dicho método con final alguna subclase que extienda de ella, esta subclase no podrá contener métodos que lo sobreescriban al primero. Si se intenta hacer esto, el compilador mostrará un error indicando "Overridden method final". Por ejemplo:

     public class ClaseBase{
          public final void agregarDato(){
                 //implementación del método
          }
     }

     public class ClaseQueExtiendeDeClaseBase extends ClaseBase{
            //ESTO NO PUEDE HACERSE:
            public void agregarDato(){
                   //otra implementación para este método sobreescrito
            }
      }

     - Por lo general, se debe evitar declarar "métodos finales". A pesar de que se podría pensar que una subclase no tendría que sobreescribir un método, no podemos estar 100% seguros de lo que otra clase quiere hacer con la nuestra.
     - Los "métodos finales" son más eficientes debido a que el compilador sabe en tiempo de compilación que una llamada a un "método final" no va a ser sobreescrito por algún otro método.
     - Los métodos privados son automáticamente considerados como "finales".

3 - Clases

Una clase con la palabra final delante, es una clase que no puede ser usada (extendida) por otra clase, es decir, no permite hacer un "extend" de ella.













La palabra reservada static en Java

En Java, vamos a llamar miembro estático a una parte de una clase (variable o método) que tenga asociada la palabra reservada “static”. Un miembro estático no está asociado con ninguna instancia de la clase que lo contenga, sino que pertenece a la clase misma. ¿Qué quiero decir con esto? Que podemos acceder a los miembros estáticos de una clase sin la necesidad de crear instancias de la misma.

Existen dos tipos de miembros estáticos como bien dijimos: variables estáticas y métodos estáticos.

Variables Estáticas:

Se trata de una variable declarada con la palabra static, por ejemplo:

      private static int contador;

Por convención, la mayoría de los programadores tienden a respetar esa estructura (visibilidad+palabra static+...) pero también funciona si colocamos la palabra static al principio de la declaración y luego la visiblidad (public, private, protected).

El valor de una variable estática es el mismo en todas las instancias de la clase. Por ejemplo, si una clase tiene una variable estática nombreDeLaEmpresa, con un valor asignado “Empresa X S.A.”, entonces todos los objetos creados desde la clase tendrán ese mismo valor “Empresa X S.A.” para esa variable nombreDeLaEmpresa.

Las variables estáticas son creadas e inicializadas cuando se carga por primera vez la clase. Esto sucede cuando un miembro estático de la clase es mencionado (Clase.miembroEstático;) o cuando se crea una instancia de la clase, lo que ocurra primero.

Métodos Estáticos:

Al igual que las variables estáticas, se trata de métodos declarados con la palabra static, por ejemplo:

     public static void calcularSaldo(int parámetro);

También están asociados con la clase misma y no con un objeto particular creado desde la clase. Es decir, no se necesita crear ningún objeto de una clase para que se puedan usar los métodos estáticos definidos en ella.

El método más conocido es el public static void main, que es llamado por la máquina virtual de Java al iniciar una aplicación. Este método debe ser estático, lo que significa que las aplicaciones se ejecutan en un contexto estático por defecto.

Sin embargo existen reglas que debemos respetar a la hora de trabajar con métodos estáticos. Una de ellas es que no se puede acceder a métodos o variables que NO SEAN estáticos desde un método estático. Esto se debe a que los métodos estáticos no tienen una instancia de la clase que es la que se utiliza para referenciar variables o métodos de instancia.





El patrón Singleton

    El singletón es un patrón de diseño que significa "instancia única". Se utiliza para restringir la creación de objetos pertenecientes a una clase (la que será nuestro Singletón) o el valor de un tipo a un único objeto.
   El objetivo principal es asegurar que la clase no pueda ser instanciada más de una única vez, es decir, garantizar que la clase sólo tenga una instancia y proporcionar un punto de acceso global a ella.
    Las situaciones más habituales de aplicación de este patrón son aquellas en las que dicha clase controla el acceso a un recurso físico único (como puede ser el ratón o un archivo abierto en modo exclusivo) o cuando cierto tipo de datos debe estar disponible para todos los demás objetos de la aplicación.
    Para crear una clase singletón, primero tenemos que pensar en el objetivo principal del mismo, o sea que solo permita crear una única instancia de la misma. Para solucionar esto, vamos a dividirlo en dos pasos:
1 - Como sabemos, la manera de crear una instancia de una clase es a través de su constructor, por ende, si el constructor de la clase es privado, ninguna otra clase tendrá acceso al mimo, por lo cual no van a poder crear instancias del mismo. Con esto tenemos solucionado que no se creen instancias de esa clase. Sin embargo, QUEREMOS crear UNA, pasemos al siguiente paso.
2 - Una vez que nuestro constructor es privado, ninguna clase externa tiene acceso al mismo, pero sí la misma clase que lo contiene, por ende, podemos crear instancias de nuestra clase desde la misma. Si escribimos un método PUBLICO que retorne una instancia de la clase, dicho método podría ser accedido desde afuera para crear instancias de la misma. El problema es nuevamente que podemos llamar tantas veces al método como queramos y con esto nuevamente vamos a poder crear muchas instancias de la clase. La solución final radica en colocar un condicional dentro del método que pregunte si ya está creada la instancia (a través de una variable), entonces retornar simplemente la misma, de lo contrario crearla por primera vez y retornarla.

Ejemplo:

public class Singleton{
   
     //creamos la variable por la cual preguntaremos en el método si es nula o no.
     private static Singleton singleton;

     //creamos nuestro constructor privado
     private Singleton(){}

     //finalmente nuestro método para retornar la instancia del Singletón
      public static Singleton getSingleton(){
          //Preguntamos si el singletón ya fue inicializado
          if(singleton==null) {
                  singleton = new  Singleton();
         }
         return singleton;
       }

}


Desde una clase externa para obtener la instancia de esa clase Singletón simplemente basta con hacer:

Singletón singletón = Singletón.getSingletón();

Es decir, acceder al método público que nos brinda la clase Singletón.

La instrumentación del patrón puede ser delicada en programas con múltiples hilos de ejecución. Si dos hilos de ejecución intentan crear la instancia al mismo tiempo y esta no existe todavía, sólo uno de ellos debe lograr crear el objeto. La solución clásica para este problema es utilizar exclusión mutua en el método de creación de la clase que implementa el patrón.

Como conclusión:
El patrón singleton provee una única instancia global gracias a que:
  -  La propia clase es responsable de crear la única instancia.
  -  Permite el acceso global a dicha instancia mediante un método de clase.
  -  Declara el constructor de clase como privado para que no sea instanciable directamente.


Saludos.


Automation: WebDriverWait en lugar de Thread.sleep

Vamos a imaginarnos que estamos ejecutando un test en una aplicación web. El test viene de lo mejor, hasta un determinado momento que nuestro código ejecuta tan rápido los pasos en la página web que hace que no nos encontramos con algún elemento que estemos buscando. Esta es la famosa NoSuchElementException. Para reducir la velocidad de la prueba uno automáticamente piensa en colocar una pausa antes de que se busque por ese elemento. Así que se coloca un bloque similar a este:

try {
    Thread.sleep(5000);
} catch (InterruptedThreadException e) {
    //manejo de la excepción
}

Si ejecutamos la prueba de nuevo, la página espera 5 segundos y luego continúa con el test. Con esto pensamos que se resolvió el problema. Sin embargo, a medida que seguimos codeando tests, escribimos bloques de "Thread.sleep" en todo el código. Al final lo que logramos es un pérdida de tiempo en la ejecución de los tests, debido a estas esperas de 5 segundos.

Entonces, ¿cuál es la solución a este problema? Existe una clase llamada WebDriverWait, que hace lo que necesitamos con un poco de inteligencia. Simplemente, basta especificarle la condición por la que estamos esperando con ExpectedCondition (en nuestro caso esperar por un elemento), y decirle la cantidad  de tiempo límite que debe esperar.

En Selenium 2.6 esta técnica es múy fácil de implementar, sin embargo voy a mostrarles como utilizarla en las versiones anteriores y posteriores a esta.


Versiones anteriores de Selenium 2.06

WebDriverWait wait = new WebDriverWait(driver, 5); // tiempo límite de espera: 5 segundos

// se espera por la condición de que el elemento "ele" esté visible en la página
ExpectedCondition<Boolean> resultsAreDisplayed = new ExpectedCondition<Boolean>() {

    public Boolean apply(WebDriver driver) {
        return driver.findElement(By.id("ele")).isDisplayed();
    }
};

wait.until(resultsAreDisplayed);



Selenium 2.06 y versiones posteriores

Se puede utilizar el código del ejemplo anterior en versiones de Selinum 2.6 y superiores, pero a partir de esta última versión, la clase ExpectedConditions brinda una serie de métodos auxiliares que nos son muchisimos más útiles:
http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html

Entonces, podemos hacer lo mismo que hicimos en el caso anterior, pero utilizando simplemente las siguientes líneas de código:

WebDriverWait wait = new WebDriverWait(driver, 5); // tiempo límite de espera: 5 segundos
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("ele")));


Simple, sencillo, fácil de implementar y mucho más óptimo.

Saludos.