Digamos que estamos haciendo un analizador. Una implementación podría ser:
public sealed class Parser1
{
public string Parse(string text)
{
...
}
}
O podríamos pasar el texto al constructor en su lugar:
public sealed class Parser2
{
public Parser2(string text)
{
this.text = text;
}
public string Parse()
{
...
}
}
El uso es simple en ambos casos, pero ¿qué significa habilitar la entrada de parámetros en Parser1
comparación con el otro? ¿Qué mensaje le envié a un compañero programador cuando mira la API? Además, ¿hay ventajas / desventajas técnicas en ciertos casos?
Otra pregunta surge cuando me doy cuenta de que una interfaz no tendría sentido en la segunda implementación:
public interface IParser
{
string Parse();
}
... donde una interfaz en la primera podría servir al menos para algún propósito. ¿Eso significa algo en particular, que una clase es "interconectable" o no?
object-oriented
interfaces
methods
construction
calentar
fuente
fuente
Respuestas:
Hablando semánticamente, en OOP solo debe pasarle al constructor un conjunto de parámetros necesarios para construir la clase; de manera similar cuando llama a un método, solo debe pasarle los parámetros que necesita para ejecutar su lógica de negocios.
Los parámetros que necesita pasar en el constructor son parámetros que no tienen un valor predeterminado sensible y si su clase es inmutable (o de hecho a
struct
), entonces se deben pasar las propiedades que no son predeterminadas.Con respecto a sus dos ejemplos:
text
al constructor, sugiere que laParser2
clase se construirá específicamente para analizar esa instancia de texto en un momento posterior. Será un analizador específico. Este suele ser el caso cuando la construcción de la clase es muy costosa o sutil, un RegEx puede compilarse en el constructor, por lo que una vez que tenga una instancia, puede reutilizarla sin tener que pagar el costo de la compilación; Otro ejemplo es la inicialización de la PRNG: es mejor si se hace raramente.text
al método, señala queParser1
se puede reutilizar para analizar diferentes textos mediante llamadas.fuente
Bueno, recordemos lo que significa pasar una variable como parámetro constructor: Inicializa un objeto para usar sus variables de instancia en los métodos del objeto. El punto es que probablemente quieras usarlo en más de un método ya que quieres tener una alta cohesión en tu clase.
Pasar un parámetro directamente a un método significa enviar un mensaje a un objeto y, probablemente, recibir una respuesta. Por eso, el cliente quiere que el objeto le brinde un servicio.
En conclusión, esos son dos medios muy diferentes de pasar parámetros y usted debe elegir si su objeto debe entregar un servicio o proporcionar alguna funcionalidad inherentemente mientras administra algo de información internamente.
fuente
Es un cambio de diseño fundamental. Y el diseño debe transmitir intención y significado. ¿Necesita tener objetos separados para cada cadena que desea analizar? En otras palabras, ¿por qué necesitamos una instancia de analizador con stringX y otra instancia con stringY? ¿Qué hay en parse (ing) y la cadena dada que los dos deben vivir y morir juntos? Suponiendo que la "implementación subyacente [análisis]" (como dice Robert Harvey) no cambia, parece que no tiene sentido. E incluso entonces es cuestionable en mi humilde opinión.
Los parámetros del constructor me dicen que estas cosas son necesarias para un objeto. El estado adecuado no está garantizado sin ellos. Además, sé cómo / por qué un analizador es fundamentalmente diferente de otro.
Los parámetros del constructor evitan que tenga que saber demasiado sobre cómo usar la clase. Si en cambio se supone que debo establecer ciertas propiedades, ¿cómo lo sé? Se abre una lata entera de gusanos. Que propiedades ¿En qué orden? Antes de usar qué métodos? y así.
Una interfaz, como en API, son los métodos y propiedades expuestos al código del cliente. No te dejes envolver
public interface { ... }
exclusivamente. Entonces, el significado de la interfaz está en el dilema del parámetro o método del constructor o del método, NOpublic interface Iparser
vspublic sealed class Parser
La
sealed
clase es rara. Si estoy pensando en diferentes implementaciones de analizador, usted mencionó "Iparser", entonces la herencia es mi primer pensamiento. Es solo una extensión conceptual natural en mi pensamiento. IE todos losParserX
s son fundamentalmenteParser
s. ¿De qué otra manera decirlo? ... Un Shepard alemán es un perro (herencia), pero puedo entrenar a mi loro a ladrar (actuar como un perro - "interfaz"); Pero Polly no es un perro, simplemente finge, después de haber aprendido un subconjunto de la ternura. Las clases, abstractas o de otro tipo, sirven perfectamente como interfaces .fuente
La segunda versión de la clase se puede hacer inmutable.
La interfaz aún se puede utilizar para proporcionar la capacidad de intercambiar la implementación subyacente.
fuente
Analizador1
Construir con un constructor predeterminado y pasar texto de entrada a un método implica que Parser1 es reutilizable.
Analizador2
Pasar el texto de entrada al constructor implica que se debe crear un nuevo Parser2 para cada cadena de entrada.
fuente