2011-01-26 6 views
5

Estoy tratando de reevaluar nuestra arquitectura n-layer y me gustaría obtener algunas sugerencias basadas en sus experiencias. Aquí está nuestro típico diseño .NET n-layer (a veces n-tier).n-layer business/service layer design

Project.UI 
Project.Services 
Project.Business 
Project.Model 
Project.DataAccess 

DataAccess consiste típicamente en Entity Framework 4 y Repository clases. Intento seguir el concepto Aggregate Root para evitar tener un repositorio para la tabla, más fácil decirlo que hacerlo en mi experiencia. Tiendo a tener ~ 70% de coincidencia entre Repositorios y Tablas.

El modelo por lo general consiste de mis entidades Entity Framework 4, he estado usando entidades EF de auto-seguimiento con éxito.

Los negocios son lo que más me cuesta. Normalmente tengo una clase Manager por cada Repository. Esta clase contendrá métodos como .Add() que realizará la validación comercial antes de reenviar a repository.Add().

Servicios, normalmente solo implementaré esto si, de hecho, estoy buscando crear una solución basada en el servicio web. Esta capa tendrá la tarea de ordenar las solicitudes/respuestas entre los DTO y las entidades. Y lo más importante es que proporciona la interfaz más coarse grained. Por ejemplo, un TradingService.SubmitTrade(), que es realmente un facade para una transacción comercial que podría incluir AccountManager.ValidateCash(), OrderManager.SubmitOrder(), etc.

Preocupaciones
Mi capa de negocio es muy entidad céntrico, realmente es solo el pegamento entre las entidades y el repositorio, con validación en el medio. He visto muchos diseños donde la capa de servicio es lo que mantiene una referencia a los repositorios (en esencia omitiendo la "capa de negocios"). En esencia, cumple el mismo propósito que mi capa de Negocios, realiza la validación, sin embargo, su "responsabilidad (y denominación) es una transacción comercial de mayor nivel y mayor tamaño. Utilizando el ejemplo anterior, TradingService.submitTrade() no delegará en ninguna clase de gerente de negocio, consultará los repositorios necesarios, realizará toda la validación, etc.

Me gusta mi diseño en el sentido de que puedo reutilizar un negocio método de capa en múltiples llamadas de servicio, sin embargo, odio el hecho de que para cada repositorio tengo un administrador de capas de negocios que coincida, creando toneladas de trabajo extra. Tal vez la solución es un tipo diferente de agrupación en el nivel Business Layer? Por ejemplo, combine clases de administrador individuales como PhoneManager y EmailManager (tenga en cuenta que tengo entidades de teléfono y entidades de correo electrónico) en una clase de administrador lógico como ContactsManager (tenga en cuenta que no tengo un tipo de entidad de "contacto"). Con métodos como ContactManager.GetPhones() y ContactManager.GetEmail(), etc.

Supongo que más que nada me pregunto cómo otros organizan y delegan responsabilidades, ya sea que tengan la capa de Servicio, la capa de Negocio, ambas, etc. Lo que contiene la referencia de contexto de ORM, etc.

Respuesta

2

Tiendo a hacer lo que describió cerca del final de sus inquietudes, y en la capa empresarial agrupo las cosas en gerentes que tienen un sentido más lógico desde el punto de vista comercial.

Usando Contactos por ejemplo, ciertamente no tendría un PhoneManager o EmailManager. "ContactsManager" es una agrupación más útil para mí, logrando casi lo mismo solo con muchos menos administradores. Desde un punto de vista comercial, los números de teléfono y los correos electrónicos son solo pequeños trozos de un Contacto de todos modos. El hecho de que tengan sus propias tablas y entidades no significa que necesiten su propio administrador. Eso no significa que no puedas reutilizarlos.Si necesita trabajar con direcciones de correo electrónico en varios lugares, ContactsManager puede tener los métodos relevantes.

Lo que tendemos a tener en nuestro entorno es una capa de base de datos/entidad, luego una capa empresarial que se ubica en el servidor y maneja las reglas comerciales y la lógica de negocios. Esa capa de negocios se expone como un servicio a través de WCF para el cliente (o al menos, es relevante para los clientes).

Parece que ya sabes lo que quieres hacer, por lo que te sugiero que hagas un poco de prototipo y veas cómo funciona para ti. :)

+0

¿Alguna vez recibió una llamada de servicio que abarca varias clases de gerente de negocios? En otras palabras, su interfaz de servicio podría ser aún más gruesa que los gerentes de negocios. Por ejemplo ContactService.CreateUser(), delegará (servirá como fachada) a UserManager.CreateUser() y ContactManager.AddEmail(), y ContactManager.AddPhone(), etc. También a pesar de que agrupamos la lógica relacionada con el correo electrónico y el teléfono en ContactsManager , no hay nada de malo en tener PhoneRepository y EmailRepository. Me parece que los repositorios no pueden ser "lógicos" como los gerentes. – e36M3

+0

Raramente, pero ha sucedido. Prefiero mantener la mayor cantidad posible de la lógica en la capa de negocios, porque eso la hace disponible si alguien viene a mí más tarde y quiere una página web que haga algunas de las mismas cosas que hace el servicio (y sí, sucede). La página web puede llamar a la misma lógica de capa de negocios que el servicio, en lugar de llamar al servicio (están en el mismo servidor en mi caso). Entonces, lo que haría en un caso como este es tener un método de gerente de negocios que pueda usar otros gerentes de negocios. Trato de evitarlo, excepto cuando hay una ganancia real en la simplicidad, sin embargo. – Tridus

+0

Sé lo que quiere decir, utilizo DI para crear mis Gerentes para proporcionarles repositorios necesarios a través del constructor. Un Gerente que crea otro Gerente requeriría que los Gerentes conozcan el contenedor DI. Sin embargo, sin esto, parece que a veces estoy duplicando la lógica copiando y pegando. Por ejemplo, DataEntryManager.EnterPrice() y FileManager.UploadPriceFile(). Usted puede imaginar que después de analizar el "archivo de precios" deberíamos insertar precios. Puedo duplicar parte de esa lógica o hacer que FileManager reutilice DataEntryManager. – e36M3