Pregunta

Soy un gran fan de NTiers para mis opciones de desarrollo, por supuesto, es imposible encajar todos los escenarios.

Actualmente estoy trabajando en un nuevo proyecto y estoy tratando de tener una obra de teatro con la forma en que normalmente el trabajo, y tratando de ver si puedo limpiarlo. Como he sido un niño muy malo y ha estado poniendo demasiado código en la capa de presentación.

Mi estructura de capas de oficina normal es este (vista básica de la misma):

  • Negocios
    • Servicios
      • FooComponent
        • FooHelpers
        • FooWorkflows
      • BahComponent
        • BahHelpers
        • BahWorkflows
    • Utilidades
      • Común
      • ExceptionHandlers
      • Importadores
      • etc ...

Ahora con lo anterior que tienen un gran acceso a directamente guardar un objeto y un objeto Foo Bah, a través de sus respectivos ayudantes.

Los XXXHelpers me da acceso a guardar, editar y cargar los objetos respectivos, pero ¿Dónde pongo la lógica para guardar objetos con los objetos secundarios.

Por ejemplo:

Tenemos los objetos a continuación (no muy buenos objetos que conozco)

  • Employee
  • EmployeeDetails
  • EmployeeMembership
  • EmployeeProfile

Actualmente me construiría estos todo en la capa de presentación y luego pasarlas a sus ayudantes, siento que esto está mal, creo que los datos deben ser transmitidos a un solo punto por encima de presentación en la capa de negocio en algún lugar y lo solucionaron allí.

Pero estoy en un poco de una pérdida en cuanto a dónde iba a poner esta lógica y lo que debe llamar el sector, habría que pasar por debajo de utilidades como EmployeeManager o algo así?

¿Qué haría usted? y sé que esto es todo preferencia.

A más detallado diseño

Los flujos de trabajo contienen todas las llamadas directamente a la DataRepository por ejemplo:

public ObjectNameGetById(Guid id)
{
    return DataRepository.ObjectNameProvider.GetById(id);
}

Y a continuación, el proveedor de acceso a los flujos de trabajo de ayudantes:

public ObjectName GetById(Guid id)
{
    return loadWorkflow.GetById(id);
}

Esto es para reducir el código duplicado, como se puede tener una llamada en el flujo de trabajo para getBySomeProperty y después de varias llamadas en el ayudante que podría hacer otras operaciones y devolver los datos de diferentes maneras, un mal ejemplo sería pública y GetByIdAsc GetByIdDesc

Por separando las llamadas al modelo de datos mediante el uso de la DataRepository, significa que sería posible cambiar el modelo para otra instancia (que era el pensamiento), pero ProviderHelper no se ha desglosado por lo que no es intercambiable, como se hardcode a EF desgracia. Yo no pretendo cambiar la tecnología de acceso, pero en el futuro puede haber algo mejor o algo que todos los niños frescos están usando ahora que puede ser que desee implementar en su lugar.

projectName.Core

projectName.Business
    - Interfaces
        - IDeleteWorkflows.cs
        - ILoadWorkflows.cs
        - ISaveWorkflows.cs
        - IServiceHelper.cs
        - IServiceViewHelper.cs
    - Services
        - ObjectNameComponent
            - Helpers
                - ObjectNameHelper.cs
            - Workflows
                - DeleteObjectNameWorkflow.cs
                - LoadObjectNameWorkflow.cs
                - SaveObjectNameWorkflow.cs
    - Utilities
        - Common
            - SettingsManager.cs
            - JavascriptManager.cs
            - XmlHelper.cs
            - others...

        - ExceptionHandlers
            - ExceptionManager.cs
            - ExceptionManagerFactory.cs
            - ExceptionNotifier.cs


projectName.Data
    - Bases
        - ObjectNameProviderBase.cs
    - Helpers
        - ProviderHelper.cs
    - Interfaces
        - IProviderBase.cs
    - DataRepository.cs

projectName.Data.Model
    - Database.edmx

projectName.Entities (Entities that represent the DB tables are created by EF in .Data.Model, this is for others that I may need that are not related to the database)
    - Helpers
        - EnumHelper.cs

projectName.Presenation

(depende de lo que la llamada de la aplicación es)

projectName.web
projectName.mvc
projectName.admin

Los proyectos de prueba

projectName.Business.Tests
projectName.Data.Test
¿Fue útil?

Solución

1 para una pregunta interesante.

Por lo tanto, el problema que usted describe es bastante común - Me gustaría tener un enfoque diferente - en primer lugar con las capas lógicas y en segundo lugar, con los espacios de nombres de servicios públicos y de ayuda, que me gustaría probar y factor por completo - Te lo diré por eso en un segundo.

Pero en primer lugar, mi enfoque preferido aquí es la arquitectura empresarial bastante común, que voy a tratar de poner de relieve, en breve, pero hay mucha más profundidad que hay. Se requiere algunos cambios radicales en el pensamiento - usando NHibernate o Entity Framework para permitirle consultar su modelo de objeto directamente y permitir que el acuerdo ORM con cosas como el mapeo hacia y desde la base de datos y las relaciones de carga diferida, etc. Hacer esto le permitirá implementar toda la lógica de negocio dentro de un modelo de dominio.

En primer lugar los niveles (o proyectos en su solución);

YourApplication.Domain

El dominio del modelo - los objetos que representan el espacio del problema. Estos son lisos viejos objetos CLR con toda la lógica de negocio clave. Aquí es donde vivirían sus objetos de ejemplo, y sus relaciones se representaría como colecciones. No hay nada en esta capa que se ocupa de la persistencia, etc., es sólo objetos.

YourApplication.Data

clases Repository - éstas son las clases que tienen que ver con la obtención de la raíz agregado (s) de su modelo de dominio.

Por ejemplo, es poco probable que en sus clases de muestra que usted desee ver en EmployeeDetails también sin mirar Empleado (un supuesto que sé, pero se obtiene lo esencial - líneas de factura es un mejor ejemplo, por lo general, se llega a la factura líneas a través de una factura en lugar de cargar de forma independiente). Como tal, las clases de depósito, de los cuales usted tiene una clase por la raíz agregada serán responsables de conseguir entidades iniciales de la base de datos utilizando el ORM en cuestión, la implementación de cualquier estrategia de consulta (como la paginación o clasificación) y devolver la raíz agregada a la consumidor. El repositorio consumiría el contexto de datos activa actual (ISession en NHibernate) -. ¿Cómo esta sesión se crea depende de qué tipo de aplicación que está construyendo

YourApplication.Workflow

  • También se puede llamar YourApplication.Services, pero esto puede confundirse con los servicios web
  • Este nivel es todo acerca de las operaciones atómicas interrelacionados y complejos -. En vez de tener un montón de cosas para ser llamados en su nivel de presentación, y por lo tanto aumentar el acoplamiento, se puede envolver este tipo de operaciones en flujos de trabajo o servicios
  • Es posible que usted podría prescindir de esto en muchas aplicaciones.

Otros niveles continuación dependen de su arquitectura y la aplicación que va a implementar.

YourApplication.YourChosenPresentationTier

Si está utilizando los servicios de Internet para distribuir sus niveles, entonces se crearía contratos DTO que representan sólo los datos que se están exponiendo entre el dominio y los consumidores. Se podría definir montadores que saber cómo mover datos dentro y fuera de estos contratos desde el dominio (que nunca enviar objetos de dominio sobre el alambre!)

En esta situación, y también se está creando el cliente, se consumiría los contratos de operación y datos definidos anteriormente en la capa de presentación, probablemente, la unión a los dtos directamente, ya que cada DTO debe ser vista específica.

Si usted no tiene ninguna necesidad de distribuir sus niveles, recordando la primera regla de arquitecturas distribuidas es no distribuyen, a continuación, se consumen los flujos de trabajo / servicios y repositorios directamente desde dentro de asp.net, mvc, WPF, WinForms etc.

Esto deja únicamente a las que se establecen los contextos de datos. En una aplicación web, cada solicitud es por lo general bastante autónomo, por lo que una petición en ámbito de contexto es mejor. Eso significa que el contexto y la conexión se establece al inicio de la solicitud y dispuesta en el extremo. Es trivial para obtener su chosen IOC / marco de inyección de dependencias de componentes de configuración por-solicitud en su nombre.

En una aplicación de escritorio, WPF o WinForms, que tendría un contexto por formulario. Esto asegura que las modificaciones a las entidades de dominio en un cuadro de diálogo de edición que la actualización del modelo, pero no la hacen a la base de datos (por ejemplo: Cancelar fue seleccionado). No interfieren con otros contextos o peor final siendo persistido accidentalmente

Inyección de dependencia

Todo lo anterior se define como interfaces de primera, con implementaciones concretas realizan a través de un marco de inyección COI y dependencia (mi preferencia es el castillo de Windsor). Esto le permite aislar, simulacros y pruebas unitarias niveles individuales de forma independiente y en una aplicación de gran tamaño, la inyección de dependencia es un protector de la vida!

Los espacios de nombres

Por último, la razón por la que iba a perder el espacio de nombres es ayudantes, en el modelo anterior, que no los necesita, sino también, al igual que los espacios de nombres de servicios que ofrecen a los desarrolladores perezosos una excusa para no pensar en donde una porción de código lógicamente sienta. . * MyApp.Helpers y MyApp.Utility. * Sólo significa que si tengo algo de código, digamos un manejador de excepciones que pertenece quizás lógicamente dentro MyApp.Data.Repositories.Customers (tal vez es una referencia al cliente no es una excepción única), un vago desarrollador simplemente puede colocarlo en MyApp.Utility.CustomerRefNotUniqueException sin realmente tener que pensar.

Si tiene código de tipo de marco común que tiene que terminar, añadir un proyecto MyApp.Framework y espacios de nombres relevantes. Si tu estás añadiendo un nuevo modelo de ligante, lo puso en MyApp.Framework.Mvc, si se trata de la funcionalidad de registro común, lo puso en MyApp.Framework.Logging y así sucesivamente. En la mayoría de los casos, no debería haber ninguna necesidad de introducir una utilidad o ayudantes espacio de nombres.

Envuélvase

Para que roza la superficie - espero que sea de alguna ayuda. Esta es la forma en que estoy desarrollando software de hoy en día, y he intentado intencionalmente para ser breves - si puedo elaborar sobre cualquier información específica, que me haga saber. La última cosa que decir sobre esta pieza obstinada es la de arriba es para el desarrollo a gran escala razonablemente - Si va a escribir el bloc de notas de la versión 2 o una guía telefónica corporativa, lo anterior es probablemente una exageración total de !!!

Saludos Tony

Otros consejos

Hay un diagrama agradable y una descripción en esta página sobre el diseño de la aplicación, aunque tuvimos apariencia más abajo en el artículo de la tampoco dividir la aplicación en capas físicas (proyecto independiente) - marco de la entidad POCO Repositorio

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top