¿Cuál es la diferencia entre los dos métodos UpdateSubject a continuación? Sentí que usar métodos estáticos es mejor si solo quieres operar en las entidades. ¿En qué situaciones debo ir con métodos no estáticos?
public class Subject
{
public int Id {get; set;}
public string Name { get; set; }
public static bool UpdateSubject(Subject subject)
{
//Do something and return result
return true;
}
public bool UpdateSubject()
{
//Do something on 'this' and return result
return true;
}
}
Sé que recibiré muchas patadas de la comunidad por esta pregunta realmente molesta, pero no pude evitar preguntarla.
¿Esto se vuelve poco práctico cuando se trata de herencia?
Actualización: está
sucediendo en nuestro lugar de trabajo ahora. Estamos trabajando en una aplicación web asp.net de 6 meses con 5 desarrolladores. Nuestro arquitecto decidió que usamos todos los métodos estáticos para todas las API. Su razonamiento es que los métodos estáticos son livianos y beneficia a las aplicaciones web al mantener baja la carga del servidor.
fuente
Respuestas:
Iré con los problemas más obvios de los métodos estáticos con parámetros explícitos "this":
Pierdes el despacho virtual y, posteriormente, el polimorfismo. Nunca puede anular ese método en una clase derivada. Por supuesto, puede declarar un método
new
(static
) en una clase derivada, pero cualquier código que acceda a él debe tener en cuenta toda la jerarquía de la clase y hacer una comprobación y conversión explícitas, que es precisamente lo que se supone que debe evitar OO .Como una extensión del n. ° 1, no puede reemplazar instancias de la clase con una interfaz , porque las interfaces (en la mayoría de los idiomas) no pueden declarar
static
métodos.La verbosidad innecesaria. ¿Cuál es más legible:
Subject.Update(subject)
o simplementesubject.Update()
?Comprobación de argumentos. Una vez más depende del lenguaje, pero muchos compilarán una verificación implícita para garantizar que el
this
argumento no seanull
para evitar que un error de referencia nulo cree condiciones de tiempo de ejecución inseguras (una especie de desbordamiento del búfer). Al no utilizar métodos de instancia, tendría que agregar esta verificación explícitamente al comienzo de cada método.Es confuso. Cuando un programador normal y razonable ve un
static
método, naturalmente asumirá que no requiere una instancia válida (a menos que requiera varias instancias, como un método de comparación o igualdad, o se espera que pueda operar connull
referencias) . Ver los métodos estáticos utilizados de esta manera nos hará hacer una doble o tal vez una toma triple, y después de la 4ta o 5ta vez estaremos estresados y enojados y Dios te ayudará si conocemos la dirección de tu casa.Es una forma de duplicación. Lo que realmente sucede cuando invoca un método de instancia es que el compilador o el tiempo de ejecución busca el método en la tabla de métodos del tipo y lo invoca usando
this
como argumento. Básicamente estás re-implementando lo que el compilador ya hace. Está violando DRY , repitiendo el mismo parámetro una y otra vez en diferentes métodos cuando no es necesario.Es difícil concebir una buena razón para reemplazar los métodos de instancia con métodos estáticos. Por favor no
fuente
File
,FileInfo
yDirectoryInfo
(y de hecho, hay bibliotecas que las ocultan detrás de interfaces que luego pueden inyectarse según sea necesario y burlarse en las pruebas).Has descrito más o menos exactamente cómo haces OOP en C, en el que solo hay métodos estáticos disponibles, y "esto" es un puntero de estructura. Y sí, puede hacer un polimorfismo de tiempo de ejecución en C especificando un puntero de función durante la construcción para almacenarlo como un elemento de la estructura. Los métodos de instancia disponibles en otros idiomas son solo azúcar sintáctico que esencialmente hace exactamente lo mismo bajo el capó. Algunos lenguajes, como python, están a mitad de camino, donde el parámetro "self" se enumera explícitamente, pero la sintaxis especial para llamarlo maneja la herencia y el polimorfismo por usted.
fuente
obj->type->mthd(obj, ...);
y eso es sustancialmente similar a lo que sucede con el despacho virtual en otros lenguajes (pero detrás de escena).El problema con el método estático llega en el momento en que necesita una subclase.
Los métodos estáticos no se pueden anular en subclases, por lo tanto, sus nuevas clases no pueden proporcionar nuevas implementaciones de los métodos, lo que los hace menos útiles.
fuente
Si declara un método
static
, no tiene que instanciar un objeto de la clase (usando lanew
palabra clave) para ejecutar el método. Sin embargo, no puede hacer referencia a ninguna variable miembro a menos que también sean estáticas, en cuyo caso esas variables miembro pertenecen a la clase, no a un objeto instanciado específico de la clase.Dicho de otra manera, la
static
palabra clave hace que una declaración forme parte de la definición de la clase, por lo que se convierte en un único punto de referencia en todas las instancias de la clase (objetos instanciados de la clase).Se deduce, entonces, que si desea múltiples copias en ejecución de su clase, y no desea que el estado (variables miembro) se comparta entre todas sus copias en ejecución (es decir, cada objeto tiene su propio estado único), entonces usted no puede declarar esas variables miembro estáticas.
En general, debe usar
static
clases y métodos solo cuando está creando métodos de utilidad que aceptan uno o más parámetros, y devuelve un objeto de algún tipo, sin ningún efecto secundario (es decir, cambios en las variables de estado en la clase)fuente
static
significa, está preguntando por qué no simplemente declarar todo como estático.Subject
- sino como un parámetro explícito, en lugar de lo implícitothis
parámetro.this
parámetro implícito . Hay diferencias en las expectativas, pero fuera de la herencia, no hay una diferencia real en lo que puede hacer. Por ejemplo, se puede acceder a esos miembros no estáticos , a través del parámetro explícito.La razón por la que las personas argumentan que los "métodos estáticos muestran un mal diseño" no se debe necesariamente a los métodos, en realidad son datos estáticos, implícitos o explícitos. Por implícito quiero decir CUALQUIER estado en el programa que no está contenido en los valores o parámetros de retorno. Modificar el estado en una función estática es un retroceso a la programación de procedimientos. Sin embargo, si la función no modifica el estado, o delega la modificación del estado a las funciones del objeto componente, en realidad es más un paradigma funcional que procesal.
Si no está cambiando de estado, los métodos y clases estáticos pueden tener muchos beneficios. Hace que sea mucho más fácil garantizar que un método sea puro y, por lo tanto, libre de efectos secundarios y cualquier error sea totalmente reproducible. También garantiza que los diferentes métodos en múltiples aplicaciones que usan una biblioteca compartida puedan estar seguros de que obtendrán los mismos resultados con la misma entrada, lo que facilita mucho el seguimiento de errores y las pruebas unitarias.
En última instancia, no hay diferencia en la práctica entre los objetos sobredimensionados que se ven comúnmente, como 'StateManager' y los datos estáticos o globales. El beneficio de los métodos estáticos utilizados correctamente es que pueden indicar la intención del autor de no modificar el estado a revisores posteriores.
fuente
making ... unit testing much easier.
No, no lo hará. Hace que sea imposible probar unitario cualquier código que llame a métodos estáticos , ya que no puede aislarlo del método estático. Una llamada a un método estático se convierte en una dependencia codificada de esa clase.Dependiendo del idioma y de lo que intente hacer, la respuesta puede ser que no hay mucha diferencia, pero la
static
versión tiene un poco más de desorden.Como su sintaxis de ejemplo sugiere Java o C #, creo que Thorbjørn Ravn Andersen tiene razón al señalar el problema primordial (con enlace tardío). Con un método estático, no existe un parámetro "especial" para que se base el enlace tardío, por lo que no puede tener un enlace tardío.
En efecto, un método estático es solo una función en un módulo, ese módulo tiene el mismo nombre que la clase; no es realmente un método OOP en absoluto.
fuente
Básicamente estás derrotando todo el punto de los objetos cuando haces esto. Hay una buena razón por la que hemos pasado del código de procedimiento al código orientado a objetos.
Yo NUNCA declarar un método estático que tuvo el tipo de clase como un parámetro. Eso solo hace que el código sea más complejo sin ganancia.
fuente
object
a unstatic
método y devuelve uno nuevoobject
. Los programadores funcionales hacen esto todo el tiempo.Math
clase estática "compleja sin ganancia", o preferiría que todos los tipos de números tuvieran métodos virtuales que definieran valor absoluto, negación, suma, cuadratura, raíces arbitrarias, etc.? No lo creo. los objetos están limpios cuando necesita almacenar un estado mutable oculto donde necesita imponer algunas invariantes. combinar todos los métodos concebibles que operan en un tipo en el tipo en sí, ESO es algo que conduce a un código complejo e imposible de mantener. Estoy de acuerdo con Robert, es posible que desee ver cómo funcionan los programadores funcionales, ¡puede ser una verdadera revelación!Aquí hay muchas respuestas geniales, y son mucho más perspicaces y conocimientos que cualquier otra cosa que se me ocurra como respuesta, pero siento que hay algo que no se está abordando:
"Nuestro arquitecto decidió que usamos todos los métodos estáticos para todas las API. Su razonamiento es que los métodos estáticos son livianos y beneficia a las aplicaciones web al mantener baja la carga del servidor ".
(El énfasis es mío)
Mi 2c en esta parte de la pregunta es esta:
Teóricamente, lo que se dice es cierto: llamar a un método estático solo tiene la sobrecarga de invocar ese método. Llamar a un método no estático (instancia) tiene la sobrecarga adicional de instanciar primero el objeto y, en algún momento, destruir la instancia (ya sea manualmente o mediante alguna forma de recolección automática de basura, dependiendo de la plataforma utilizada).
Juega un poco del abogado del diablo en esto: podemos ir más allá y decir cosas como:
esto puede llegar a ser realmente malo si se crea una instancia para cada invocación del método (instancia) (en lugar de dejarlo estático y llamarlo así)
dependiendo de la complejidad del constructor, la jerarquía de tipos, otros miembros de la instancia y otros factores desconocidos, la sobrecarga adicional de la llamada al método no estático puede variar y llegar a ser realmente grande
En verdad, en mi humilde opinión, los puntos anteriores (y el enfoque general de "usemos las estadísticas porque son más rápidas") son argumentos / evaluaciones de hombre de paja:
si el código es bueno y, más específico para este argumento, si las instancias se crean solo cuando es necesario (y se destruyen de manera óptima), entonces no obtiene ningún gasto adicional por usar métodos de seguro cuando sea apropiado (porque si solo cree los objetos necesarios, esos se habrían creado incluso si ese método se declarara como estático en algún otro lugar = misma sobrecarga de instanciación)
Al abusar de la declaración de métodos estáticos de esta manera, es posible ocultar algunos problemas con su código con respecto a cómo se crean las instancias (dado que el método es estático, un código de instancia incorrecto puede pasar desapercibido hasta más tarde, y eso nunca es bueno).
fuente
Esta es una pregunta muy interesante que tiende a tener respuestas muy diferentes dependiendo de la comunidad a la que se la pregunte. Otras respuestas parecen ser C # o sesgo de Java: un lenguaje de programación que está orientado (principalmente) a objetos puros y tiene una especie de visión idiomática de lo que es la orientación a objetos.
En otras comunidades, como C ++, la orientación a los objetos se interpreta con más liberalidad. Algunos bien saben que los expertos han estudiado el tema y, en realidad, concluyen que las funciones libres mejoran la encapsulación (el énfasis es mío):
Para aquellos que no están familiarizados con la terminología de C ++:
Ahora, para responder tu pregunta:
No, no siempre debes usar métodos estáticos.
Pero, debe usarlos siempre que solo necesite usar la API pública de una clase.
fuente
en Java ...
Los métodos estáticos no se sobrescriben, sino que se ocultan, por lo que sería una gran diferencia (¿problema?) En el caso de extender la clase.
Por otro lado, noté que los programadores de Java tienden a pensar que TODO TIENE que ser un objeto, sin entender realmente por qué, y no estoy de acuerdo.
Estático debe usarse para código específico de la clase. La estática no funciona bien con la herencia.
Algunos buenos ejemplos de uso de métodos estáticos son funciones independientes sin efectos secundarios.
ver también la palabra clave sincronizada ...
fuente