2011-01-18 12 views
9

Estoy trabajando en un proyecto de tipo de red social en OO PHP y no quiero usar un marco existente. El objetivo principal de este proyecto es ayudarme a aprender sobre más cosas.¿Son demasiadas dependencias para inyectar en un objeto a través del constructor?

Esta pregunta es más acerca de la inyección de dependencia.

Digamos que tengo estas clases:

clase principal - algunos métodos básicos para hacer cosas en la aplicación
config clase - cosas cargas sitio config
clase de base de datos - se conecta a MySQL y todas las cosas relacionadas con la base de datos
clase de registrador - se utiliza para registrar errores y depurar información
clase código de imagen - para el código de imagen en las formas
sesión de clase - inicia un inicio de sesión y agrega, quita, pone las variables de sesión para usar en la aplicación
clase caché - archivos similar a la clase de sesión pero para cachés artículos (caché, memcache, apc cache. Incluso puedo agregar mi material de sesión a esta clase algún día ya que todos estos cachés pueden usar el mismo tipo de métodos)

Todas las clases anteriores probablemente se usarán en cada carga de página en mi aplicación (probablemente me perdí algunas clases más) que se agregará más adelante)

Ahora, además de las clases anteriores que deberán incorporarse en la mayoría de las otras clases, tendré muchas más clases. Tendré una sección llamada módulos que tendrá cosas como ...

cuenta clase - crea nuevos usuarios, autentica usuarios, registra usuarios dentro y fuera de la aplicación, actualiza la configuración del usuario y mucho más.
usuarios de clase - muestra los perfiles de los usuarios, muestra a los usuarios en línea, los nuevos usuarios, todas las cosas que mostrar a los usuarios del sitio
foros clase - será para la sección de foros
blogs clase - para la sección de blogs
clase fotos - todas las cosas relacionadas con foto
comentarios clase - maneja los comentarios para las fotos y los perfiles

Habrá muchas más de este tipo de clases para diferentes secciones del sitio.
Este segundo conjunto de clases enumeradas anteriormente para las secciones muy probablemente requerirá que la mayoría de las clases del primer conjunto sean inyectadas en ellas.

¿Debo usar un registro para almacenar los objetos del primer conjunto de clases y simplemente insertar el registro en todos los objetos de clase en el segundo conjunto de clases?

¿O debería usar el constructor para cargarlos? En este ejemplo, habría como 7 objetos para inyectar en las otras clases, eso parece mucho. ¿Estoy haciendo esto mal?

--- --- EDITAR
Soy consciente del patrón singleton, pero no creo que es mi mejor opción aquí

--- --- EDIT 2
Como algunos han mencionado, la necesidad de pasar tanto como 7 objetos parece MUCHO y es por eso que estoy buscando sugerencias. Por suerte para mí, este proyecto está en las etapas iniciales, por lo que ahora es el momento de realizar cambios en la estructura.

Un ejemplo sería una clase en la sección de mis foros. La clase de foros necesitaría acceso a datos de sesión, posibles datos en caché, el objeto configs, objeto de base de datos. ¿Voy por esto de la manera incorrecta?

+0

Relacionado: http://stackoverflow.com/questions/2420193/dependency-injection-constructor-madness –

+0

Eliminado mi respuesta, porque usted lo mencionó también. Ir con el patrón de registro. – mhitza

+0

Si sus objetos necesitan 7 objetos para ser inyectados solo para funcionar, cuestionaré la arquitectura subyacente de esas clases. Lo ideal es que solo necesites un par de objetos. Alternativamente, los envases de Inyección de Dependencia pueden aliviar parte de su estrés ... personalmente, no soy un fanático. – CaseySoftware

Respuesta

11

¿O debería usar el constructor para cargarlos? En este ejemplo, habría como 7 objetos para inyectar en las otras clases, eso parece mucho. ¿Estoy haciendo esto mal?

Cuando empieces a necesitar inyectar tantos objetos, debes preguntarte si el objeto que los recibe es responsable de demasiado. ¿Se puede dividir en pedazos más pequeños?

Si realmente no puede, entonces considere encapsular objetos relacionados en otra clase. Tal vez sus objetos session, logger y config pueden ser inyectados en un objeto App o Application?

Edit: Noto que la mayoría de las otras respuestas hasta ahora hablan sobre Singletons. Tenga en cuenta que los Singletons son enemigo de DI. Gran charla técnica de Google en este here.

Edición 2:

Lo que quiero decir mediante la encapsulación es decir, en lugar de inyectar Session, Logger, Config, etc., todo en su clase Account, tal vez se debe inyectar en una clase Application, y un Application instancia puede ser inyectado en Account.

Para ser sincero, esto sigue siendo una pieza de DI. Me estoy volviendo loco, pero lo que estoy empezando a ver es esto: solo debe inyectar en Account los objetos que necesitará manipular directamente. Es posible que esos objetos necesiten manipular otros objetos, pero Account no necesita saber nada al respecto.


A menudo, sin embargo, ni siquiera necesitará tantas "capas" como pensaba. Si descubre que está inyectando material por todas partes, considere diversas formas de reestructurar su aplicación. Déjame sacar un trozo de código de la documentación de los pilones de la variante:

a = model.Person() 
a.name = "Aaa" 
a.email = "[email protected]" 
meta.Session.add(a) 

(. No se preocupe por meta.Session ... básicamente se encarga de la interacción con la base de datos)

Aquí, creamos una instancia de una Person, establezca algunos de sus atributos y guárdelo. Notarás que la clase Person sabe nada sobre la base de datos, y de hecho ni siquiera tiene un método save(). En cambio, lo pasamos a la clase de base de datos (meta.Session) que lo guarda. Hemos separado la preocupación por la lógica Person del código de la base de datos. meta.Session podría funcionar de una docena de maneras diferentes, pero mientras sepa cómo leer Person, estamos bien. (en este caso, durante la inicialización de la aplicación, lee la definición de todos los modelos de la aplicación).


Bien, voy a resumir, porque obviamente divagué mucho aquí. No hay una respuesta "correcta" para su pregunta (hasta donde yo sé, pero no pretendo ser un experto en DI de ninguna manera).

Sí, la inyección de varios objetos es probablemente alguna indicación de necesidad de reestructurar, pero hay una serie de consideraciones a realizar:

  • es el objeto de recibir la inyección responsable de demasiado; puede ser separado?
  • ¿Está inyectando solo objetos que la clase destinataria necesitará utilizar directamente?
  • ¿Está inyectando en la dirección incorrecta? ¿Puede su objeto Account inyectarse en su Database en lugar de al revés?
+0

Agregué un poco a mi OP, pero ¿a qué te refieres con "encapsular objetos relacionados en otra clase" – JasonDavis

+0

mi comentario es cada vez más largo, así que voy a editarlo en mi respuesta original ... – keithjgrant

+1

+1 La ventaja de la inyección de dependencia es que cosas como el Logger, que la clase de la cuenta no debe saber cómo crear, se pueden proporcionar desde otro lugar. Si se pueden crear instancias de muchas de estas cosas durante una inicialización configurable y compatible con el entorno de su clase de aplicación, inyectar la aplicación le brinda un buen paquete ordenado. Y no tendrá que cambiar cada constructor en su proyecto cuando agregue una clase nueva y ampliamente utilizada. – grossvogel

-2

Siempre he preferido el enfoque de registro.

Razones:

  • temas más amplios
  • sencilla de obtener
  • constructores son liberados de tener objetos como variables (permite un mejor uso)
  • permite utilizar más objetos en sus clases como su libre para agarrar lo que necesita, cuando lo desee.

Aunque hay otro método que puede probar y eso es mediante el patrón singleton, donde tendría un método en cada clase que realiza un seguimiento de su propio objeto.

Fors ejemplo, crear una interfaz de este modo:

interface ISingleton 
{ 
    public static getInstnace(); 
} 

Entonces, para cada objeto puede agregar el método que se utiliza para el conseguir de la instancia.

class SomeObject implements ISingleton, ISomeThingElse 
{ 
    private static $_instance; 
    public static getInstance() 
    { 
     if(self::$_instance === null) 
     { 
      self::$_instance = new SomeObject(); 
     } 
     return self::$_instance; 
    } 
} 

De esta manera siempre conservará su misma instancia del objeto y tendrá un alcance global.

Ejemplo:

public function GetUser($id) 
{ 
    return Database::getInstance()->fetchUserById($id); 
} 

Espero que esto ayude.


Hay otra manera de hacerlo y eso es la creación de una clase de contexto, permítanme tratar de explicar:

La clase actuaría como un registro pero solo uso, por ejemplo:

class Context 
{ 
    private $objects = array(); 

    public function Add($key,$Object) 
    { 
     $this->objects[$key] = $object; 
    } 

    public function __get($key) 
    { 
     return isset($this->objects[$key]) ? $this->objects[$key] : null; 
    } 
} 

y usar eso como un envase para guardar sus objetos de esta manera:

$Context = new Context(); 
$Context->Add("database",$database); 
$Context->Add("logger",$logger); 
$Context->Add("session",$session); 

$UserObject = new RegularUser($Context); 

esta manera se puede agrupe un conjunto de objetos y pase el mismo contexto en varios otros objetos de la biblioteca.

+8

-1 Esta es la antítesis de la inyección de dependencia, y es una decisión de diseño * horrible *. – cdhowie

+0

Por favor, publique una respuesta que explique su propuesta. – RobertPitt

+0

He utilizado código como este en el pasado, pero espero mejorar mi código, así que estoy buscando otras alternativas – JasonDavis

Cuestiones relacionadas