java - ¿Los mejores diseños para analizar la lógica de negocios y la capa de datos cuando parecen superponerse?
design model-view-controller (2)
Estoy construyendo una aplicación web MVC (utilizando el marco Spring MVC), y estoy un poco perplejo sobre la mejor manera de diseñar un área en particular.
La aplicación tiene que interactuar con una serie de servicios web que no están realmente diseñados en gran medida, y no ofrecen mucha abstracción en sí mismos; básicamente, hay un método de servicio web para cada operación de creación / actualización / recuperación / eliminación para cada "tipo de datos", y no hay mucho de una API más allá de eso. El cliente del servicio web necesita saber qué métodos invocar y en qué orden, para poder crear los datos que necesita, es decir, no hay métodos basados en "transacciones".
Por ejemplo, simplemente para crear una nueva cuenta de usuario es necesario llamar a un total de siete diferentes métodos de servicio web para configurar todos los registros en las tablas necesarias (un registro de user
, agregar los privileges
correctos a ese usuario, configurar los detalles de billing
del usuario) , etc.)
Estoy luchando con la mejor manera de abstraer esto y encapsularlo dentro de nuestra aplicación. La mayoría de la aplicación sigue un flujo estándar:
request ---> Controller <---> Service/Business-level object <---> DAOs for data access
Dentro de mi aplicación, estoy usando mi propio conjunto de "objetos de dominio" para representar y abstraer los tipos de datos definidos en el WSDL del servicio web, para que mi lógica de dominio no dependa de los tipos de servicio web y para que podamos abstraer y ocultar cualesquiera detalles que nos gusten
En lo que estoy buscando algunas opiniones es en la mejor forma de diseñar el "proceso de creación de usuarios" que mencioné anteriormente como ejemplo. El proceso para crear un "usuario regular" implica llamar a siete servicios web diferentes, como mencioné, pero este es solo un "tipo" de usuario: tendremos que ser capaces de crear diferentes tipos de usuarios, cada uno de los cuales requiere diferentes servicios web a invocar.
Actualmente solo he diseñado esta creación de "usuario habitual", como una pequeña prueba de concepto: tengo un User
objeto de dominio, una interfaz UserDao
que tiene métodos para getUser(name)
y createUser(User)
, y un WebServiceUserDao
que implementa los métodos UserDao
y sabe cómo invocar los siete métodos de servicio web mencionados anteriormente. El método createUser()
es llamado por un UserCreationService
, que es mi clase business / service-level, que a su vez es invocada por el SignupController
.
Pero para ampliar esta lógica para poder crear los diferentes tipos de usuario (que están representados por diferentes valores en User.getType()
, no estoy seguro de dónde trazar la línea entre la clase de capa de servicio / negocio y el DAO. Por ejemplo, debería yo:
- Cree una implementación de
UserDao
por "tipo de usuario", para que la lógica para crear cada "tipo de usuario" pueda ser encapsulada en su propia clase, y permita queUserCreationService
decida quéUserDao
usará. Esto correspondería a 1 clase de servicio: muchos DAO. - ¿Debería dividir el
UserDao
en partes más pequeñas, una correspondiente a cada "registro" que debe crearse en el servicio web / base de datos, a pesar de que mi aplicación general no necesita saber acerca de cada uno de estos tipos individuales? ¿Y luego tienen diferentes implementaciones deUserCreationService
para los diferentes "tipos de usuario"? En otras palabras, esta estrategia tendría unPrivilegesDao
, unBillingPlanDao
, etc., a pesar de que no necesitaría un objeto de dominioPrivilege
oBillingPlan
correspondiente. Esta sería muchas clases de servicio: muchos DAO. - ¿Contiene toda la lógica para la cual los servicios web necesitan ser llamados para cada "tipo de usuario" en un solo
WebServiceUserDao
? Esto tendría el inconveniente de tener una clase muy complicada (y el PMD ya se está quejando de la complejidad ciclomática), pero toda esta lógica estaría encapsulada en una clase y podría conducir a una menor complicación si se considera desde una perspectiva API global.
Uno de los objetivos que tengo con esta aplicación es asegurarme de que si alguna vez tenemos que cambiar los detalles de la persistencia de los datos, todo lo que tenemos que hacer es cambiar las implementaciones de DAO, si tenemos que empezar a interactuar con un sistema de facturación diferente, No quiero cambiar ninguna parte de la aplicación que no sea en el nivel DAO.
Alguna opinion? ¿Qué tipo de estrategias usas para decidir dónde descomponer la "lógica comercial" frente a la "lógica de acceso a los datos" cuando parecen superponerse?
¿Qué tipo de estrategias usas para decidir dónde descomponer la "lógica comercial" frente a la "lógica de acceso a los datos" cuando parecen superponerse?
Tal vez puedas tener tres capas en lugar de dos: "un nivel adicional de indirección".
En la capa superior, es posible que tenga una lógica comercial que desconoce el acceso a los datos: esta capa empresarial usa clases como User
, Account
, etc., y tal vez algunos métodos de fábrica, como User.getAccounts
y Account.getOwners
.
La capa inferior puede ser una capa de acceso a datos, que es su envoltura o fachada a lo que sea que sea su capa de datos.
Entre estas dos capas, una capa que sabe cuáles son sus objetos comerciales (por ejemplo, usuario y cuenta) pero no cuál es su lógica comercial. La capa intermedia conoce tu capa de acceso a datos. El trabajo de su capa intermedia es usar la API de su capa de acceso a datos para E / S de sus objetos comerciales.