java - programacion - ¿Está escribiendo "esto" antes de la variable de instancia y los métodos son buenos o malos?
manual de programacion android pdf (20)
A veces me gusta escribir clases como esta:
class SomeClass{
int x;
int y;
SomeClass(int x, int y){
this.x = x
this.y = y
}
}
Esto hace que sea más fácil decir qué argumento está configurando qué miembro.
Uno de mis malos hábitos de programación (?) En C ++ y Java es siempre preceder llamadas o accesos a miembros con this
. Por ejemplo: this.process(this.event)
.
Algunos de mis alumnos comentaron sobre esto, y me pregunto si estoy enseñando malos hábitos.
Mi razonamiento es:
- Hace que el código sea más legible: es más fácil distinguir los campos de las variables locales.
- Hace que sea más fácil distinguir las llamadas estándar de las llamadas estáticas (especialmente en Java)
- Me hace recordar que esta llamada (a menos que el objetivo sea final) podría terminar en un objetivo diferente, por ejemplo, en una versión predominante en una subclase.
Obviamente, esto tiene un impacto cero en el programa compilado, es solo legibilidad. Entonces, ¿lo estoy haciendo más o menos legible?
Nota: Lo convertí en un CW ya que realmente no hay una respuesta correcta.
Creo que es menos legible, especialmente en entornos donde los campos se destacan de forma diferente a las variables locales. El único momento en que quiero ver "esto" es cuando es necesario, por ejemplo:
this.fieldName = fieldName
Cuando se asigna el campo.
Dicho esto, si necesita alguna manera de diferenciar los campos por alguna razón, prefiero "this.fieldName" a otras convenciones, como "m_fieldName" o "_fieldName"
Desde una perspectiva .Net, algunas de las herramientas de análisis de código que utilicé vieron el "esto" y de inmediato concluyeron que el método no podía ser estático. Puede ser algo para probar con Java, pero si hace lo mismo allí, podría faltar algunas mejoras de rendimiento.
En mi opinión, lo estás haciendo más legible. Permite a los posibles solucionadores de problemas futuros saber si la función a la que llama es verdadera.
En segundo lugar, no es imposible tener una función con el mismo nombre global o de algún espacio de nombres que se "usa" ''en conflicto. Entonces, si hay un conflicto, el autor del código original sabrá con certeza a qué función están llamando.
Concedido que si hay conflictos de espacio de nombres, se está rompiendo alguna otra regla de codificación limpia, pero nadie es perfecto. Por lo tanto, creo que cualquier regla que no impida la productividad, tiene el potencial de reducir errores (sin importar cuán minúsculo sea el potencial), y podría hacer que una futura solución de problemas sea más fácil, es una buena regla.
Más legible, creo. Lo hago a tu manera por exactamente las mismas razones.
No es un mal hábito en absoluto. No lo hago yo mismo, pero siempre es una ventaja cuando noto que alguien más lo hace en una revisión del código. Es un signo de calidad y legibilidad que muestra que el autor está codificando con un proceso de pensamiento dedicado, no solo pirateando.
Solía usar siempre esto ... Entonces, un compañero de trabajo me señaló que, en general, nos esforzamos por reducir el código innecesario, ¿no debería aplicarse esa regla también aquí?
Yo diría que lo más importante es la consistencia. Hay argumentos razonables a favor y en contra, por lo que es sobre todo una cuestión de gusto al considerar qué enfoque.
"Legibilidad"
He encontrado útil el uso de "esto" especialmente cuando no se usa un IDE (pequeños programas rápidos)
Cuando mi clase es lo suficientemente grande como para delegar algunos métodos a una nueva clase, reemplazar "this" con "otherRef" es muy fácil con el editor de texto más simple.
es decir
//Before
this.calculateMass();
this.perfornmDengerAction();
this.var = ...
this.other = ...
Después del "refactor"
// after
this.calculateMass();
riskDouble.calculateMass();
riskDouble.setVar(...);
this.other = ...
Cuando uso un IDE, generalmente no lo uso. Pero creo que te hace pensar de una manera más OO que simplemente usar el método.
class Employee {
void someMethod(){
// "this" shows somethings odd here.
this.openConnectino() ; // uh? Why an employee has a connection???
// After refactor, time to delegate.
this.database.connect(); // mmhh an employee might have a DB.. well..
}
... etc....
}
Lo más importante, como siempre, es que si un equipo de desarrollo decide usarlo o no, esa decisión se respeta.
Encuentro que menos es más. Mientras más basura innecesariamente detallada tenga en su código, más problemas tendrá la gente para mantenerla. Dicho esto, tener un comportamiento claro y consistente también es importante.
La gente de Python lo hace todo el tiempo y casi todos lo prefieren. Lo deletrean a sí mismo en lugar de ''esto''. Hay formas de evitarlo, pero el consenso es que el "yo" explícito es esencial para comprender el método de clase.
Lo uso por al menos dos razones:
Falacias razones
Me gusta tener estilos de código consistentes al codificar en C ++, C, Java, C # o JavaScript. Me mantengo usando el mismo estilo de codificación, principalmente inspirado en Java, pero inspirado por los otros idiomas.
También me gusta mantener una coherencia dentro de mi código en un idioma. Utilizo typename
para los parámetros de tipo de plantilla, en lugar de class
, y nunca juego el mezclador con los dos. Esto significa que odio tener que agregar this
en un punto, pero lo evito por completo.
Mi código es bastante verbo. Los nombres de mis métodos pueden ser largos (o no). Pero siempre usan nombres completos, y nunca nombres compactados (es decir, getNumber()
, no getNbr()
).
Estas razones no son lo suficientemente buenas desde un punto de vista técnico, pero aún así, esta es mi forma de codificación, e incluso si no (muy) bien, no hacen (mucho) mal. De hecho, en la base de código en la que trabajo hay más anti-patrones históricos escritos por otros para permitirles cuestionar mi estilo de codificación.
Para cuando aprendan a escribir "excepción" o "clase", pensaré en todo esto, nuevamente ...
Razones reales
Si bien aprecio el trabajo del compilador, hay algunas ambigüedades en las que me gustaría hacer ambigüedades de la ONU.
Por ejemplo, yo (casi) nunca uso el using namespace MyNamespace
. Uso el espacio de nombre completo o uso un alias de tres letras. No me gustan las ambigüedades, y no me gusta cuando el compilador de repente me dice que también hay funciones que "imprimen" colisionando juntas.
Esta es la razón por la que prefijo las funciones de Win32 por el espacio de nombres global, es decir, siempre escribo ::GetLastError()
lugar de GetLastError()
.
Esto va de la misma manera para this
. Cuando uso this
, restrinjo conscientemente la libertad del compilador para buscar un símbolo alternativo si no encontraba el verdadero. Esto significa métodos, así como las variables miembro.
Al parecer, esto podría usarse como argumento contra la sobrecarga de métodos. Pero esto solo sería aparente. Si escribo métodos sobrecargados, quiero que el compilador resuelva la ambigüedad en tiempo de compilación. Si no escribo this
palabra clave, no es porque quiera que el compilador use otro símbolo distinto al que tenía en mente (como una función en lugar de un método, o lo que sea).
¿Mi conclusión?
En general, este problema es principalmente de estilo y con razones técnicas genuinas. No querré la muerte de alguien que no escriba this
.
En cuanto a la cita de Bruce Eckel de su "Thinking Java" ... no me impresionaron las comparaciones tendenciosas Java / C ++ que sigue haciendo en su libro (y la ausencia de comparación con C #, extrañamente), así que su punto de vista personal sobre this
, hecho en una nota al pie ... Bien ...
Nunca había visto este estilo hasta que me uní a mi empleador actual. La primera vez que lo vi pensé "este idiota no tiene idea y los lenguajes Java / OO generalmente no son su fuerte", pero resulta que es una afección que ocurre regularmente aquí y es un estilo obligatorio en un par de proyectos, aunque estos proyectos también usan el
if (0 == someValue)
{
....
}
enfoque para hacer condicionales, es decir, colocar la constante primero en la prueba para que no corras el riesgo de escribir
if (someValue = 0)
por accidente, un problema común para los codificadores C que ignoran las advertencias del compilador. La cosa es que, en Java, lo anterior es simplemente un código no válido y será eliminado por el compilador, por lo que en realidad están haciendo que su código sea menos intuitivo sin ningún beneficio en absoluto.
Para mí, por lo tanto, lejos de mostrar que "el autor está codificando con un proceso de pensamiento dedicado", me parece más probable que provenga del tipo de persona que se apega a las reglas que alguien más le dijo una vez sin cuestionarlas ni saber las razones de las reglas en primer lugar (y por lo tanto donde las reglas no deberían aplicarse).
Las razones que he escuchado se reducen a "es una buena práctica", por lo general citando Java efectivo de Josh Bloch, que tiene una gran influencia aquí. De hecho, sin embargo, Bloch ni siquiera lo usa donde incluso creo que probablemente debería tener que ayudar a la legibilidad. Una vez más, parece ser más el tipo de cosas que hacen las personas a las que se les dice que lo hagan y ¡no saben por qué!
Personalmente, me inclino a estar más de acuerdo con lo que dice Bruce Eckel en Thinking in Java (3ª y 4ª ediciones):
"Algunas personas pondrán esto obsesivamente delante de cada llamada de método y referencia de campo, argumentando que lo hace" más claro y más explícito ". No lo hagas Hay una razón por la que usamos lenguajes de alto nivel: hacen cosas por nosotros. Si ingresas esto cuando no es necesario, confundirás y molestarás a todos los que leen tu código, ya que todo el resto del código que han leído no usará esto en todas partes. La gente espera que esto se use solo cuando sea necesario. Seguir un estilo de codificación coherente y directo ahorra tiempo y dinero ".
nota al pie, p169, Pensando en Java, 4ª edición
Bastante. Menos es más, gente.
Prefiero el modo de asignación local descrito anteriormente, pero no para las llamadas a métodos locales. Y estoy de acuerdo con los sentimientos de ''consistencia es el aspecto más importante''. Encuentro esto. Algo más legible, pero encuentro la codificación consistente aún más legible.
public void setFoo(String foo) {
this.foo = foo; //member assignment
}
public doSomething() {
doThat(); //member method
}
Tengo colegas que prefieren:
public void setFoo(String foo) {
_foo = foo;
}
Si va a eliminar la necesidad de agregar esto. frente a las variables miembro, las herramientas de análisis estático como el estilo de control pueden ser invaluables para detectar casos en los que las variables miembro ocultan campos. Al eliminar esos casos, puede eliminar la necesidad de usar esto en primer lugar. Dicho esto, prefiero ignorar estas advertencias en el caso de los constructores y los instaladores en lugar de tener que encontrar nuevos nombres para los parámetros del método :).
Con respecto a las variables estáticas, encuentro que los IDEs más decentes destacarán estos para que pueda diferenciarlos. También vale la pena usar una convención de nomenclatura para cosas como constantes estáticas. Las herramientas de análisis estático pueden ayudar aquí haciendo cumplir las convenciones de nomenclatura.
Encuentro que rara vez hay confusión con los métodos estáticos ya que las firmas de métodos a menudo son lo suficientemente diferentes como para hacer innecesaria cualquier otra diferenciación.
Tengo que unirme al campo ''incluir esto'' aquí; No lo hago de manera consistente, pero desde el punto de vista del mantenimiento, los beneficios son obvios. Si el mantenedor no usa un IDE por el motivo que sea y, por lo tanto, no tiene campos y métodos de miembros especialmente resaltados, entonces se encontrará con un mundo de dolor de desplazamiento.
3 Razones (traje Nomex ENCENDIDO )
1) Estandarización
2) Legibilidad
3) IDE
1) The biggie No forma parte del estilo del código Sun Java.
(No es necesario tener ningún otro estilo para Java).
Entonces no lo hagas (en Java)
Esto es parte de lo de Java de cuello azul: siempre es el mismo en todas partes.
2) Legibilidad
Si quieres esto. Tener esto. Esto enfrente de cada esto. Esta otra palabra; ¿realmente crees esto? ¿Crees que esto mejora?
Si hay demasiados métodos o variables en una clase para saber si es miembro o no ... refactor.
Solo tiene variables miembro y no tiene variables o funciones globales en Java. (En otros langunages puede tener punteros, desbordamiento de matriz, excepciones sin marcar y variables globales también; disfrute)
Si desea saber si el método está en la clase principal de su clase o no ... recuerde poner @Override en sus declaraciones y deje que el compilador le informe si no lo reemplaza correctamente. super.xxxx () es un estilo estándar en Java si desea llamar a un método principal, de lo contrario, omítelo.
3) IDE Cualquier persona que escriba código sin un IDE que entienda el idioma y dé un bosquejo en la barra lateral puede hacerlo en su propio níquel. Al darse cuenta de que si no es sensible al lenguaje, estás atrapado en la década de 1950. Sin una GUI: atrapado en los años 50.
Cualquier IDE o editor decente le dirá de dónde viene una función / variable. Incluso el VI original (<64kb) hará esto con CTags. Simplemente no hay excusa para usar herramientas de mierda. ¡Los buenos se regalan gratis!
menos legible a menos que, por supuesto, sus estudiantes todavía estén en terminales de pantalla verde, como los estudiantes aquí ... la élite tiene una gran sintaxis.
Acabo de escuchar el rumor de que también tienen herramientas de refactorización, lo que significa que no necesitas "esto". para buscar y reemplazar, y pueden eliminar esas pesquisadas redundantes con una sola pulsación de tecla. aparentemente estas herramientas pueden incluso dividir métodos, por lo que son agradables y cortas como deberían haber sido al principio, la mayoría de las veces, y luego es obvio incluso para un detector verde que los vars son campos.
Hay una buena razón técnica para preferir usar o evitar this
: los dos no siempre son equivalentes.
Considera el siguiente código:
int f();
template <typename T>
struct A
{
int f();
};
template <typename T>
struct B : A<T>
{
int g()
{
return f();
return this->f();
}
};
Ahora, hay dos llamadas f()
en B<T>::g()
. Uno esperaría que llamara a A<T>::f()
, pero solo el segundo lo hará. El primero llamará ::f()
. La razón detrás de esto es que debido a que A<T>
depende de T
, la búsqueda normalmente no lo encuentra. this
, al ser un puntero a B<T>
, también depende de T
, por lo que si lo usas, la búsqueda se retrasará hasta que se haya instanciado B<T>
.
Tenga en cuenta que este comportamiento puede no estar presente en algunos compiladores (específicamente, MSVC) que no implementan la búsqueda de nombre de dos fases, pero no obstante es el comportamiento correcto.
Esto es algo muy subjetivo. Microsoft StyleCop tiene una regla que requiere esto. calificador (aunque está relacionado con C #). Algunas personas usan guiones bajos, algunas usan notaciones húngaras extrañas. Personalmente califico a los miembros con esto. incluso si no se requiere explícitamente para evitar confusiones, porque hay casos en que puede hacer que el código sea un poco más legible.
Es posible que también desee verificar esta pregunta:
¿Qué tipo de prefijo usas para las variables miembro?