2010-09-23 19 views
5

Uso el Scanner class para leer múltiples archivos similares. Me gustaría extenderlo para asegurarme de que todos usan el mismo delimitador y también puedo agregar métodos como skipUntilYouFind (String thisHere) que son todos válidos para todos.¿Por qué la clase java.util.Scanner es declarada 'final'?

Puedo hacer una clase de utilidad que los contenga, o incorporar la clase de escáner como una variable dentro de otra clase, pero esto es más engorroso.

He encontrado some reasons para declarar una clase final, pero ¿por qué se hace aquí?

+0

Si esto está relacionado con el rendimiento, ¿sería posible en teoría hacer un escáner que no funciona y que sea extensible? Mi lógica dice que debería ser? – Roalt

Respuesta

4

Probablemente porque ampliarlo y sobrescribir algunos de sus métodos probablemente lo rompa. Y hacer que sea más fácil sobrescribir los métodos expondría a gran parte del funcionamiento interno, por lo que si en el futuro deciden cambiarlos (por rendimiento u otras razones), sería más difícil para ellos cambiar la clase sin romper todas las clases que lo extienden

Por ejemplo, consideremos el siguiente método en la clase:

public boolean nextBoolean() { 
    clearCaches(); 
    return Boolean.parseBoolean(next(boolPattern())); 
} 

decir que quiere sobrescribir esto porque quiere hacer 'impresionante' evaluar a un valor lógico 'verdadero' (por cualquier motivo). Si lo sobreescribe, no puede llamar a super.nextBoolean(), ya que eso consumiría el siguiente token usando la lógica predeterminada. Pero si no llama a super.nextBoolean(), no se invocará clearCaches(), posiblemente rompiendo los otros métodos no sobrescritos. No puedes llamar a clearCaches() porque es privado. Si lo protegieron, pero luego se dieron cuenta de que estaba causando un problema de rendimiento, y querían una nueva implementación que ya no borrara los cachés, entonces podrían romper su implementación sobreescrita, lo que aún llamaría eso.

Básicamente es para que puedan cambiar fácilmente las partes ocultas dentro de la clase, que son bastante complejas, y lo protegen de hacer una clase secundaria rota (o una clase que podría romperse fácilmente).

+0

Eso explicaría por qué la función nextBoolean debería definirse como 'booleano público final nextBoolean()', no toda la clase? – Roalt

+0

Sí, pero podría tener un método que no tenga clearCaches() y no se declare como definitivo, pero se dan cuenta de que también necesitan agregar clearCaches(), pero ahora no pueden declararlo definitivo. (ya que rompería las clases ampliándolo).Y muchos (si no todos los métodos) confían mucho en la implementación oculta de todos modos (muchos de ellos deberían ser finales desde el principio). Es simplemente más fácil, y tiene más sentido declarar que todo es definitivo (ya que las partes que deberían ser definitivas podrían cambiar al cambiar la implementación interna). –

+1

Según esta lógica, todo debería ser una clase final. No puedo honestamente creer que esta es la razón. – corsiKa

0

Creo que el enlace que proporcionó lo explica todo.

En su caso, parece que debería preferir la composición en lugar de la herencia de todos modos. Está creando una utilidad que tiene un comportamiento predefinido y que puede ocultar algunos (o todos) los detalles de la clase de escáner.

He visto muchas implementaciones que utilizan la herencia para cambiar un comportamiento. El resultado final fue generalmente un diseño monolítico, y en algunos casos, un contrato roto y/o un comportamiento roto.

+0

Hacerlo una composición aumentará el tamaño de mi código. No es un pecado, pero obtendrás my.scanner.next() (o incluso my.getScanner(). Next() en lugar de my.next(). Creo que es menos hermoso, ¿no? Y es menos "reemplaza esto "por" que "... – Roalt

+0

Bueno, si tiene que suObject.scanner.next() entonces eso no es encapsulación ¿verdad? Pero si usted tiene un YourObject.process (input): returnVal entonces lo hace. –

1

Supongo que es por razones de seguridad. Esta clase lee la entrada del usuario, para que alguien con malas intenciones pueda extenderla, modificar su comportamiento y te arruinarían. Si es final, no es tan fácil para el malo, porque si él hace su propio tipo de escáner (no java.util.Scanner), los principios del polimorfismo se romperían. Ver al malo puede ser lo suficientemente inteligente como para escribir un bot/script que lo hace automáticamente en servidores remotos ... Incluso puede hacerlo mediante la carga de clases dinámica en una aplicación compilada.

Cuestiones relacionadas