Clase con método único - mejor enfoque?


Digamos que tengo una clase que está destinada a realizar una sola función. Después de realizar la función, puede ser destruido. ¿Hay alguna razón para preferir uno de estos enfoques?

// Initialize arguments in constructor
MyClass myObject = new MyClass(arg1, arg2, arg3);
myObject.myMethod();

// Pass arguments to method
MyClass myObject = new MyClass();
myObject.myMethod(arg1, arg2, arg3);

// Pass arguments to static method
MyClass.myMethod(arg1, arg2, arg3);

Estaba siendo intencionalmente vago acerca de los detalles, para tratar de obtener pautas para diferentes situaciones. Pero realmente no tenía en mente funciones de biblioteca simples como Matemáticas.aleatorio(). Estoy pensando más en clases que realizan alguna tarea específica y compleja, pero solo requieren un método (público) para hacerlo se.

Author: Robert Harvey, 2008-10-15

14 answers

Me encantaban las clases de utilidad llenas de métodos estáticos. Hicieron una gran consolidación de métodos auxiliares que de otra manera estarían alrededor causando redundancia y un infierno de mantenimiento. Son muy fáciles de usar, sin instanciación, sin eliminación, solo fire'n'forget. Supongo que este fue mi primer intento involuntario de crear una arquitectura orientada a servicios: muchos servicios sin estado que simplemente hicieron su trabajo y nada más. Como un sistema crece sin embargo, dragones ser próximos.

Polimorfismo
Digamos que tenemos el método UtilityClass.Algún método que zumbe alegremente. De repente tenemos que cambiar ligeramente la funcionalidad. La mayor parte de la funcionalidad es la misma, pero tenemos que cambiar un par de partes sin embargo. Si no hubiera sido un método estático, podríamos hacer una clase derivada y cambiar el contenido del método según sea necesario. Como es un método estático, no podemos. Seguro, si solo necesitamos agregar funcionalidad antes o después del método anterior, podemos cree una nueva clase y llame a la vieja dentro de ella , pero eso es asqueroso.

Problemas de interfaz
Los métodos estáticos no se pueden definir a través de interfaces por razones lógicas. Y como no podemos anular métodos estáticos, las clases estáticas son inútiles cuando necesitamos pasarlas por su interfaz. Esto nos hace incapaces de usar clases estáticas como parte de un patrón de estrategia. Podríamos arreglar algunos problemas pasando delegados en lugar de interfaces .

Pruebas
Esto básicamente va de la mano con los problemas de interfaz mencionados anteriormente. Como nuestra capacidad de intercambiar implementaciones es muy limitada, también tendremos problemas para reemplazar el código de producción con el código de prueba. Una vez más, podemos envolverlos, pero requerirá que cambiemos grandes partes de nuestro código solo para poder aceptar envoltorios en lugar de los objetos reales.

Fosters blobs
Como métodos estáticos se utilizan generalmente como métodos de utilidad y los métodos de utilidad generalmente tendrán diferentes propósitos, terminaremos rápidamente con una clase grande llena de funcionalidad no coherente-idealmente, cada clase debería tener un solo propósito dentro del sistema. Preferiría tener un cinco veces las clases siempre y cuando sus propósitos estén bien definidos.

Parámetro fluencia
Para empezar, ese pequeño método estático lindo e inocente podría tomar un solo parámetro. A medida que la funcionalidad crece, se agregan un par de nuevos parámetros. Pronto se agregan parámetros adicionales que son opcionales, por lo que creamos sobrecargas del método (o simplemente agregamos valores predeterminados, en idiomas que los admiten). En poco tiempo, tenemos un método que toma 10 parámetros. Solo los tres primeros son realmente necesarios, los parámetros 4-7 son opcionales. Pero si se especifica el parámetro 6, también se requiere que se rellene el 7-9... Si hubiéramos creado una clase con el único propósito de hacer lo que hizo este método estático, podríamos resolver esto tomando los parámetros requeridos en el constructor, y permitiendo al usuario establecer valores opcionales a través de propiedades, o métodos para establecer múltiples valores interdependientes al mismo tiempo. Además, si un método ha crecido a esta cantidad de complejidad, lo más probable es que necesite estar en su propia clase de todos modos.

Exigir a los consumidores que creen una instancia de clases sin ninguna razón
Uno de los argumentos más comunes es, por qué exigir que los consumidores de nuestra clase creen una instancia para invocar este método único, mientras que no utilizar para la instancia después? Crear una instancia de una clase es una operación muy, muy barata en la mayoría de los idiomas, por lo que la velocidad no es un problema. Agregar una línea adicional de código al consumidor es un bajo costo para sentar las bases de una solución mucho más mantenible en el futuro. Y finalmente, si desea evitar la creación de instancias, simplemente cree un contenedor singleton de su clase que permita una fácil reutilización, aunque esto hace que el requisito de que su clase sea apátrida. Si no sin estado, aún puede crear métodos de envoltura estática que manejen todo, al tiempo que le brinda todos los beneficios a largo plazo. Finalmente, también podría hacer una clase que oculta la instanciación como si fuera un singleton: MyWrapper.Instance es una propiedad que solo devuelve new MyClass ();

Solo un Sith trata en absolutos
Por supuesto, hay excepciones a mi aversión por los métodos estáticos. Las verdaderas clases de utilidad que no presentan ningún riesgo de hincharse son casos excelentes para métodos estáticos-Sistema.Convertir como ejemplo. Si su proyecto es único sin requisitos para el mantenimiento futuro, la arquitectura general realmente no es muy importante, estática o no estática, realmente no importa, sin embargo, la velocidad de desarrollo sí.

¡Estándares, estándares, estándares!
El uso de métodos de instancia no le impide utilizar también métodos estáticos, y viceversa. Siempre y cuando haya un razonamiento detrás de la diferenciación y esté estandarizado. Hay nada peor que mirar por encima de una capa de negocio en expansión con diferentes métodos de implementación.

 237
Author: Mark S. Rasmussen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 21:03:38

Prefiero la forma estática. Dado que la Clase no representa un objeto, no tiene sentido hacer una instancia de él.

Las clases que solo existen para sus métodos deben dejarse estáticas.

 80
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-15 16:30:19

Si no hay razón para tener una instancia de la clase creada para ejecutar la función, utilice la implementación estática. Por qué hacer que los consumidores de esta clase creen una instancia cuando no es necesaria.

 15
Author: Ray Jezek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 17:46:11

Si no necesita guardar el estado del objeto, entonces no hay necesidad de instanciarlo en primer lugar. Me gustaría ir con el único método estático que pasar parámetros a.

También advertiría contra una clase Utils gigante que tiene docenas de métodos estáticos no relacionados. Esto puede ser desorganizado y difícil de manejar a toda prisa. Es mejor tener muchas clases, cada una con pocos métodos relacionados.

 12
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 18:24:30

Realmente no sé cuál es la situación aquí, pero me gustaría ponerlo como un método en una de las clases a las que pertenecen arg1,arg2 o arg3 If Si puedes decir semánticamente que una de esas clases poseería el método.

 5
Author: Chris Cudmore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 17:46:27

Yo diría que el formato de método estático sería la mejor opción. Y haría la clase estática también, de esa manera no tendrías que preocuparte por crear accidentalmente una instancia de la clase.

 5
Author: Nathen Silver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 17:46:37

Sugeriría que es difícil de responder basado en la información proporcionada.

Mi intuición es que si solo vas a tener un método, y que vas a tirar la clase inmediatamente, entonces hazlo una clase estática que tome todos los parámetros.

Por supuesto, es difícil decir exactamente por qué necesita crear una sola clase solo para este método. ¿Es la típica situación de "clase de utilidades" como la mayoría está asumiendo? ¿O estás implementando algún tipo de clase de regla, de que podría haber más en el futuro.

Por ejemplo, haga que esa clase sea conectable. Entonces querrías crear una Interfaz para tu único método, y luego querrías tener todos los parámetros pasados a la interfaz, en lugar de al constructor, pero no querrías que fuera estático.

 4
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 21:12:19

¿Puede su clase ser estática?

Si es así, entonces lo haría una clase 'Utilities' en la que pondría todas mis clases de una función.

 3
Author: Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 17:45:20

Si este método es sin estado y no necesita pasarlo, entonces tiene más sentido definirlo como estático. Si necesita pasar el método, podría considerar usar un delegado en lugar de uno de sus otros enfoques propuestos.

 3
Author: Joel Wietelmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 18:58:44

Para aplicaciones simples y ayudantes internal, usaría un método estático. Para aplicaciones con componentes, me encanta Managed Extensibility Framework. Aquí hay un extracto de un documento que estoy escribiendo para describir los patrones que encontrarás en mis API.

  • Servicios
    • Definido por una interfaz I[ServiceName]Service.
    • Exportado e importado por el tipo de interfaz.
    • La implementación única es proporcionada por la aplicación host y consumida internamente y / o por extensiones.
    • Los métodos en la interfaz de servicio son seguros para subprocesos.

Como un ejemplo artificial:

public interface ISettingsService
{
    string ReadSetting(string name);

    void WriteSetting(string name, string value);
}

[Export]
public class ObjectRequiringSettings
{
    [Import]
    private ISettingsService SettingsService
    {
        get;
        set;
    }

    private void Foo()
    {
        if (SettingsService.ReadSetting("PerformFooAction") == bool.TrueString)
        {
            // whatever
        }
    }
}
 3
Author: Sam Harwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-15 18:05:30

Simplemente haría todo en el constructor. así:

new MyClass(arg1, arg2, arg3);// the constructor does everything.

O

MyClass my_object(arg1, arg2, arg3);
 2
Author: pravprab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-06 10:19:18

Una cuestión más importante a considerar es si el sistema se ejecutaría en un entorno multiproceso, y si sería seguro para subprocesos tener un método estático o variables...

Debe prestar atención al estado del sistema.

 0
Author: NZal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-27 07:49:40

Usted podría ser capaz de evitar la situación todos juntos. Intenta refactorizar para que obtengas arg1.myMethod1(arg2, arg3). Intercambio arg1 con arg2 o arg3 si tiene más sentido.

Si no tienes control sobre la clase de arg1, decórala:

class Arg1Decorator
    private final T1 arg1;
    public Arg1Decorator(T1 arg1) {
        this.arg1 = arg1;
    }
    public T myMethod(T2 arg2, T3 arg3) {
        ...
    }
 }

 arg1d = new Arg1Decorator(arg1)
 arg1d.myMethod(arg2, arg3)

El razonamiento es que, en OOP, los datos y los métodos de procesamiento de esos datos pertenecen juntos. Además obtienes todas las ventajas que Mark mencionó.

 0
Author: Hugo Wood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-31 14:36:51

Creo que, si las propiedades de su clase o la instancia de clase no se utilizarán en constructores o en sus métodos, no se sugiere que los métodos se diseñen como patrón 'estático'. el método estático siempre debe pensarse en' ayuda'.

 0
Author: user7545070,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-10 09:39:41