2009-01-19 16 views
23

Tengo un pequeño problema de arquitectura. En mi proyecto, tengo una capa de lógica de negocios (BLL) que contiene todas mis reglas comerciales, modelos y API OO para la interfaz. Cada objeto tiene métodos estáticos como getById que devuelven una instancia de dicho objeto. Cada objeto también tiene métodos como guardar y eliminar. Este es un código OO muy sencillo.Nivel de lógica empresarial Capa y acceso a datos: dependencia circular

Ahora tengo una capa de DataAccess (DAL), contenida en un espacio de nombre separado, para cada objeto BLL tengo una DataClass o "Repositorio" que ejecuta los comandos getById y save. Entonces, de alguna manera, los métodos save y getById de BLL son una capa delgada alrededor de los métodos de DataClass.

public static NewsItem GetByID(int id) 
{ 
     return DataFactory.GetNewsItemRepository().GetNewsItemById(id); 
} 

Para que las DataClasses devuelvan objetos BLL, necesitan conocer el BLL. por lo que ahora tenemos:

GUI ---> BLL < ----> DAL

El DataFactory sólo devuelve objetos que implementan una interfaz, por lo que puede ocultar los detalles de implementación como “OracleNewsItemRepository”.

Pero ahora lo que me molesta desde que comencé la programación orientada a objetos. En mi solución actual, tanto BLL como DAL necesitan conocerse entre sí. Esta es una Dependencia Circular, y es una buena práctica evitar dependencias circulares. También solo quiero exponer las interfaces (y mi DataFactory) y no mis clases. Esto se puede hacer colocando la capa DAL en un ensamble separado. Lo cual tendría sentido. Sin embargo, Visual Studio no permite que dos Ensambles se refieran entre sí. Otra pregunta sobre esto: C# internal access modifiers

De alguna manera creo que tengo mi patrón de acceso a datos completo mal. Parece que estoy convulsionando el patrón ActiveRecord con otras cosas como DataMappers. He pasado mucho tiempo en el sitio de Martin Fowler, pero esos patrones se describen muy genéricos y se ilustran con un diagrama UML muy abstracto.

No resuelven mi problema. Tal vez soy un poco anal, y no existe el "patrón perfecto de acceso a datos". Y lo que hago ahora no parece terriblemente mal. Pero cómo hago las cosas ahora, parece estar fuera de contexto ...

¿Alguna idea?

Respuesta

11

Creo que su patrón de acceso a datos está bien. Lo que no está haciendo es acoplar su BLL con OracleDAL. Estás uniendo las interfaces DAL. Es absolutamente necesario un poco de acoplamiento o nunca se puede hacer nada.

Supongo que las clases DataFactory y INewsItemRepository existen fuera de su capa DAL. El siguiente es un ejemplo de cómo están organizadas mis soluciones. No uso ActiveRecord, por lo que puede que no te quede perfectamente.

 
Core (Project) 
    Domain 
    Business Entities 
    Data 
    Repository Interfaces 
    **Your DataFactory** 

OracleData (Project) 
    Data 
    Oracle Repository Implementations 

SqlData (Project) 
    Data 
    Sql Repository Implementations 

UI (Project) 

Espero que esto ayude.

+0

Trabajos, en combinación con DI. Mi BLL ahora solo conoce las interfaces. – IceHeat

11

En mi opinión:

La capa de acceso a datos (DAL) debe operar en POCOs (Plain Old CLR Object) mediante operaciones tales como: SaveNewsItem (NewsItemDAO newsItemDAO). Los POCO son sus DAO (Objetos de acceso a datos).

La capa empresarial debe contener la lógica para convertir un objeto de acceso a datos (DAO) en un objeto comercial enriquecido, que probablemente sea solo el DAO más algunas operaciones, así como cualquier decoración/enriquecimiento.

El DAL no debería tener ningún conocimiento sobre la capa de lógica de negocios. En teoría, debería poder ser llamado desde cualquier cliente. Por ejemplo, ¿qué pasaría si quisiera separar el DAL de la aplicación y desplegarlo como un servicio independiente que se expone a través de WCF?

Como se mencionó, las operaciones DAL, p. Ej. El BO debe tener acceso a SaveNewsItem a través de las interfaces, quizás a través de la inyección de dependencia/IoC.

+0

Sí, estoy de acuerdo, es mejor que el DAL no sepa sobre el BLL. En cambio, el DAL debe tener algún tipo de abstracción para que el BLL pueda construir sus entidades a partir de "datos brutos", es decir, DAO (o XML o un mapa de pares clave/valor, por ejemplo). Estas fábricas están mejor separadas de la lógica del dominio –

5

Puede usar interfaces/inyección de dependencia para resolver su problema.

Su capa empresarial (BL) contiene las interfaces de acceso a datos (DA) que el (posiblemente más de un) DAL necesita implementar. Los proyectos DAL tienen referencias de proyecto a BL para que puedan escupir objetos comerciales (BO) e implementar las interfaces DA.

Sus BO pueden llamar a DataFactory, que puede instanciar un objeto DA mediante inyección o reflexión de dependencia.

He utilizado este patrón en muchas de nuestras aplicaciones aquí en el trabajo (tanto basado en la web y el cliente inteligente), y funciona muy bien.

+0

. Voy a intentarlo. – IceHeat

2

Para que quede claro, me gusta pensar en un modelo de negocio y lógica de negocios como dos capas separadas. Su modelo de negocio son sus POCO (objetos simples de CLR antiguos). Su capa de lógica de negocios sería responsable de realizar validaciones, transacciones, etc. utilizando tanto su modelo de negocio como una interfaz para su DAL que podría conectarse de varias maneras (Spring, Castle o su propio contenedor IoC).

Una buena manera de lograr cero dependencias en su DAL con su modelo de negocio es utilizar un marco de mapeo de relaciones de objeto (ORM) ya construido como NHibernate (un enchufe desvergonzado para mi marco ORM favorito).

+0

Traidor. Todo el mundo sabe que EF es como un millón de veces mejor que NHiberanate. [agachándose para cubrirse] – Jake

+1

Excepto con EF, no puede tener un modelo de negocio que no dependa de EF. – Trent

+1

¿La capa comercial es responsable de las transacciones? NO, están hechos en DAL. Solo una excepción: transacciones distribuidas. – Pascal

0

DAL debe ser abstracto, por lo que debe contener solo objetos ADO.NET simples que interactúen con la base de datos backend, por ejemplo, la conexión DataAdapter, DataReader, etc. Con eso a mano puede hacer referencia a DAL en su capa Biz, y cuando se trata de sus entidades con un poco de abstracción puede resolver todos sus problemas, por ejemplo, si tiene clase de cliente, puede crear una clase de cliente abstaractoin que implemente las operaciones básicas para interactuar con DAL, como guardar, actualizar y recuperar datos, y en otra clase que hereda la clase de abstracción, anulan la implementación de métodos de clase base para cumplir con su validación de Biz, etc.

2

IceHeat, el ejemplo de @Craig Wilson tiene más sentido y es probablemente derivado de este artículo: http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx.

Esto es BIEN digno de leer y aborda el desarrollo impulsado por dominio que resuelve los problemas que se enfrentan aquí. Lo recomendaría a cualquiera, incluso si no le das a un mono sobre NHibernate es un gran artículo.

+0

Ese es un gran artículo. No estoy seguro de dónde vino la estructura del proyecto, pero he leído muchas veces el "Diseño impulsado por el dominio" de Eric Evan, así que ... –

1

Me gustaría eliminar cualquier get() y el método Save() de usted BLL (modelo de dominio) .. Esto es lo que haría

interfaz gráfica de usuario le pedirá Repositorio de conseguir objeto de dominio por id .. y una vez GUI tiene el objeto de dominio que podría navegar para llegar a otros objetos ... De esta manera, la capa de dominio no necesita saber nada sobre los repositorios ...

Dentro del repositorio puede devolver el objeto de dominio que carga o carga por completo el gráfico del objeto objeto. Esto dependerá de lo que necesite ...

Aquí hay una buena reseña sobre el mismo tema ...Reconstituting objects

Leer el comentario de Deyan Petrov sobre el uso de proxy dinámico

3

Es un poco viejo ahora, pero tal vez debería haber considerado poner en Pocos de los/interfaces en otro montaje.

Project.Data references Project.Entities 
Project.BL references Project.Entities and Project.Data 
Project.UI references Project.Entities and Project.BL 

Aquí no hay referencias circulares.

Cuestiones relacionadas