La respuesta a continuación es incorrecta, pero la guardaré para que otros aprendan de ella (ver más abajo)
En ExampleA
, puede usar la misma Config
instancia en varias clases. Sin embargo, si debería haber solo una Config
instancia dentro de la aplicación completa, considere aplicar el patrón Singleton Config
para evitar tener múltiples instancias de Config
. Y si Config
es un Singleton, puede hacer lo siguiente en su lugar:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
En ExampleB
, por otro lado, siempre obtendrá una instancia separada de Config
para cada instancia de ExampleB
.
La versión que debe aplicar realmente depende de cómo la aplicación manejará las instancias de Config
:
- si cada instancia de
ExampleX
debe tener una instancia separada de Config
, vaya con ExampleB
;
- si cada instancia de
ExampleX
compartirá una (y solo una) instancia de Config
, use ExampleA with Config Singleton
;
- si las instancias de
ExampleX
pueden usar diferentes instancias de Config
, quédese con ExampleA
.
Por qué está mal convertirse Config
en Singleton :
Debo admitir que ayer aprendí sobre el patrón Singleton (leyendo el libro de patrones de diseño Head First ). Ingenuamente me puse en práctica y lo apliqué para este ejemplo, pero como muchos han señalado, una forma es otra (algunas han sido más crípticas y solo dijeron "¡Lo estás haciendo mal!"), Esta no es una buena idea. Entonces, para evitar que otros cometan el mismo error que acabo de cometer, aquí sigue un resumen de por qué el patrón Singleton puede ser dañino (según los comentarios y lo que descubrí buscando en Google):
Si ExampleA
recupera su propia referencia a la Config
instancia, las clases estarán estrechamente acopladas. No habrá forma de tener una instancia de ExampleA
usar una versión diferente de Config
(digamos alguna subclase). Esto es horrible si quieres probar ExampleA
usando una instancia de maqueta Config
ya que no hay forma de proporcionarla ExampleA
.
La premisa de que habrá una, y solo una, instancia de Config
tal vez se mantenga ahora , pero no siempre puede estar seguro de que lo mismo se mantendrá en el futuro . Si en algún momento posterior resulta que Config
serán deseables múltiples instancias de , no hay forma de lograr esto sin reescribir el código.
A pesar de que la instancia de one-and-only-one Config
es tal vez cierta para toda la eternidad, puede suceder que desee poder usar alguna subclase de Config
(mientras todavía tenga una sola instancia). Pero, dado que el código obtiene directamente la instancia a través getInstance()
de Config
, que es un static
método, no hay forma de obtener la subclase. Nuevamente, el código debe ser reescrito.
El hecho de que los ExampleA
usos Config
estarán ocultos, al menos cuando solo esté viendo la API de ExampleA
. Esto puede o no ser algo malo, pero personalmente siento que esto se siente como una desventaja; por ejemplo, cuando se realiza el mantenimiento, no existe una forma simple de averiguar a qué clases se verán afectados los cambios Config
sin analizar la implementación de todas las demás clases.
Incluso si el hecho de que ExampleA
use un Singleton Config
no es un problema en sí mismo, puede convertirse en un problema desde el punto de vista de la prueba. Los objetos Singleton llevarán un estado que persistirá hasta la finalización de la aplicación. Esto puede ser un problema al ejecutar pruebas unitarias, ya que desea que una prueba esté aislada de otra (es decir, que haber ejecutado una prueba no debería afectar el resultado de otra). Para solucionar esto, el objeto Singleton debe destruirse entre cada ejecución de prueba (potencialmente tener que reiniciar toda la aplicación), lo que puede llevar mucho tiempo (sin mencionar tedioso y molesto).
Dicho esto, me alegro de haber cometido este error aquí y no en la implementación de una aplicación real. De hecho, estaba considerando reescribir mi último código para usar el patrón Singleton para algunas de las clases. Aunque podría revertir fácilmente los cambios (todo está almacenado en un SVN, por supuesto), todavía habría perdido el tiempo haciéndolo.