¿No puedo usar todos los métodos estáticos?

63

¿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 parte de la comunidad por esta pregunta realmente molesta, pero no pude evitar preguntarme.

¿Esto se vuelve imprá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 ligeros y benefician a las aplicaciones web al mantener la carga del servidor baja.

    
pregunta Alexander 03.08.2011 - 01:20

10 respuestas

83

Iré con los problemas más obvios de los métodos estáticos con parámetros "este" explícitos:

  1. Pierdes el envío virtual y, posteriormente, el polimorfismo. Nunca puedes 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 ser consciente de toda la jerarquía de clases y realizar una comprobación y conversión explícitas, que es precisamente lo que se supone que OO evita .

  2. Como una extensión de # 1, no puede reemplazar las instancias de la clase con una interfaz , porque las interfaces (en la mayoría de los idiomas) no pueden declarar los métodos static .

  3. La verbosidad innecesaria. ¿Qué es más legible: Subject.Update(subject) o simplemente subject.Update() ?

  4. Comprobación de argumentos. De nuevo, depende del idioma, pero muchos compilarán una comprobación implícita para asegurarse de que el argumento this no sea null para evitar que un error de referencia nulo cree condiciones de tiempo de ejecución inseguras (tipo de saturación de búfer). Si no utiliza métodos de instancia, tendrá que agregar esta comprobación explícitamente al comienzo de cada método.

  5. Es confuso. Cuando un programador normal y razonable ve un método static , naturalmente asumirá que no requiere una válida instancia (a menos que tome varias instancias, como un método de comparación o igualdad, o se espera que sea capaz de operar en null referencias). Ver los métodos estáticos utilizados de esta manera nos hará realizar una doble o quizás triple toma, y después de la 4ª o 5ª vez estaremos estresados y enojados, y Dios lo ayudará si sabemos la dirección de su casa.

  6. 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 buscan el método en la tabla de métodos del tipo y lo invocan usando this como argumento. Básicamente estás re-implementando lo que el compilador ya hace. Estás violando DRY , repitiendo el mismo parámetro una y otra vez en diferentes métodos cuando no es necesario.

Es difícil concebir una razón buena para reemplazar los métodos de instancia con métodos estáticos. Por favor, no.

    
respondido por el Aaronaught 03.08.2011 - 02:06
12

Usted ha descrito bastante exactamente cómo hace la POO en C, en la que solo hay métodos estáticos disponibles, y "esto" es un puntero a estructura. Y sí, puede hacer polimorfismo de tiempo de ejecución en C especificando un puntero de función durante la construcción para que se almacene como un elemento de la estructura. Los métodos de instancia disponibles en otros idiomas son solo azúcar sintáctica que esencialmente hace exactamente lo mismo bajo el capó. Algunos idiomas, como python, están a medio camino, donde el parámetro "self" está explícitamente en la lista, pero la sintaxis especial para llamarlo maneja la herencia y el polimorfismo para usted.

    
respondido por el Karl Bielefeldt 03.08.2011 - 05:20
10

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, haciéndolos menos útiles.

    
respondido por el user1249 03.08.2011 - 01:30
7

Si declara un método static , no tiene que crear una instancia de un objeto de la clase (usando la palabra clave new ) para ejecutar el método. Sin embargo, no puede referirse a ninguna variable miembro a menos que también sean estáticas, en cuyo caso esas variables miembro pertenecen a la clase, no es un objeto instanciado específico de la clase .

Dicho de otra manera, la palabra clave static 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 desde la clase) .

De ello 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 no puede declarar esas variables miembro estáticas.

En general, debe usar las clases y métodos static solo cuando esté creando métodos de utilidad que acepten uno o más parámetros, y devuelva un objeto de algún tipo, sin efectos secundarios (es decir, cambios a las variables de estado en la clase)

    
respondido por el Robert Harvey 03.08.2011 - 01:29
3

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 me refiero a CUALQUIER estado en el programa que no esté contenido en los valores o parámetros de retorno. La modificación del 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 de procedimiento.

Si no está cambiando el estado, los métodos estáticos y las clases 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 completamente reproducible. También garantiza que los diferentes métodos en múltiples aplicaciones que utilizan una biblioteca compartida pueden garantizar que obtendrán los mismos resultados si se les da la misma información, lo que hace que el seguimiento de errores y las pruebas unitarias sean mucho más fáciles.

En última instancia, no hay diferencia en la práctica entre los objetos de gran tamaño vistos 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 los revisores posteriores.

    
respondido por el Mathieson 29.02.2012 - 04:51
2

Básicamente estás derrotando todo el punto de los objetos cuando haces esto. Hay una buena razón por la que prácticamente hemos pasado del código de procedimiento al código orientado a objetos.

Yo NUNCA declararía un método estático que tomó el tipo de clase como un parámetro. Eso solo hace que el código sea más complejo para ninguna ganancia.

    
respondido por el Loren Pechtel 03.08.2011 - 04:05
2

Esta es una pregunta muy interesante que tiende a tener respuestas muy diferentes dependiendo de la comunidad que la esté preguntando. Otras respuestas parecen ser C # o java bias: un lenguaje de programación que (en su mayoría) está orientado a objetos puros y tiene una especie de vista idiomática de lo que es la orientación a objetos.

En otras comunidades, como C ++, la orientación a objetos se interpreta con más liberalidad. Algunos expertos saben que han estudiado el tema y, en realidad, concluyen que las funciones gratuitas mejoran la encapsulación (el énfasis es mío):

  

Ahora hemos visto que una forma razonable de medir la cantidad de   encapsulación en una clase es contar el número de funciones que   podría romperse si la implementación de la clase cambia. Ese ser el   caso, queda claro que una clase con n funciones miembro es más   encapsulado que una clase con n + 1 funciones miembro. Y eso   la observación es lo que justifica mi argumento para preferir a no miembros   Funciones que no son de amigo a funciones de miembro

     

Scott Meyers

Para aquellos que no están familiarizados con la terminología de C ++:

  • función miembro = método
  • función no miembro = método estático
  • non-friend = usa solo API pública
  • función no amiga no miembro = método estático que usa solo API pública

Ahora, para responder tu pregunta:

  

¿No puedo usar todos los métodos estáticos?

No, no siempre debes usar métodos estáticos.

Pero, debes usarlos cuando solo necesites usar la API pública de una clase.

    
respondido por el authchir 30.07.2013 - 17:53
1

Dependiendo del idioma y de lo que intenta hacer, la respuesta puede ser que no hay mucha diferencia, pero la versión static 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 de la anulación (con enlace tardío). Con un método estático, no hay un parámetro "especial" en el que se pueda basar el enlace tardío, por lo que no puede haber 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, en realidad no es un método OOP.

    
respondido por el Steve314 03.08.2011 - 01:49
1

Hay muchas respuestas geniales aquí, y son mucho más perspicaces y conocedoras que cualquier otra cosa que pueda encontrar como respuesta, pero creo 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 ligeros y beneficia a las aplicaciones web al mantener la carga del servidor baja ."

(el énfasis en negrita es mío)

Mi 2c en esta parte de la pregunta es la siguiente:

Teóricamente, lo que se dice allí es verdad: llamar a un método estático solo tiene el costo de invocar ese método. La invocación de un método no estático (instancia) tiene la sobrecarga adicional de la primera instanciación del objeto y, en algún momento, destruye la instancia (ya sea manualmente o mediante algún tipo de recolección automática de basura, dependiendo de la plataforma utilizada).

El juego es un poco del defensor del diablo sobre esto: podemos ir aún más lejos y decir cosas como:

  • esto puede volverse 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, el tipo hyerarchy, otros miembros de instancia y otros factores desconocidos, la sobrecarga adicional de la llamada al método no estático puede variar y ser realmente grande

En verdad, en mi humilde opinión, los puntos anteriores (y el enfoque general de "vamos a usar estadísticas porque son más rápidos") son argumentos y evaluaciones de paja:

  • si el código es bueno y, más específicamente a este argumento, si las instancias se crean solo cuando es necesario (y se destruyen de una manera óptima), entonces no obtiene ningún costo adicional por el uso de métodos de seguridad. cuando sea apropiado (porque si solo creas los objetos necesarios, esos se habrían creado incluso si ese método fuera declarado como estático en algún otro lugar = la 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 (ya que el método es estático, un código de instanciación incorrecto puede pasar inadvertido hasta más tarde, y eso nunca bueno).

respondido por el Shivan Dragon 30.07.2013 - 16:57
-3

en Java ...

Los métodos estáticos no se sobrescriben, sino que se ocultan en su lugar, por lo que sería una gran diferencia (¿problema?) en el caso de ampliar la clase.

Por otra parte, noté que los programadores de Java tienen una tendencia a pensar que todo TIENE QUE ser un objeto, sin entender realmente por qué, y no estoy de acuerdo.

Se debe usar Static para el 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.

también vea la palabra clave sincronizada ...

    
respondido por el Nicolas 17.06.2015 - 17:58

Lea otras preguntas en las etiquetas