Estoy diseñando una aplicación simple basada en la web. Soy nuevo en este dominio basado en la web. Necesitaba su consejo con respecto a los patrones de diseño, como cómo se debe distribuir la responsabilidad entre los Servlets, los criterios para hacer nuevos Servlet, etc.
En realidad, tengo pocas entidades en mi página de inicio y, en correspondencia con cada una de ellas, tenemos pocas opciones como agregar, editar y eliminar. Anteriormente estaba usando un Servlet por opciones como Servlet1 para agregar entidad1, Servlet2 para editar entidad1, etc. y de esta manera terminamos teniendo una gran cantidad de servlets.
Ahora estamos cambiando nuestro diseño. Mi pregunta es cómo elige exactamente cómo elige la responsabilidad de un servlet. Deberíamos tener un Servlet por entidad que procesará todas sus opciones y reenviará la solicitud a la capa de servicio. ¿O deberíamos tener un servlet para toda la página que procesará toda la solicitud de la página y luego la reenviará a la capa de servicio correspondiente? Además, si el objeto de solicitud se reenvía a la capa de servicio o no.
fuente
Respuestas:
Una aplicación web un poco decente consiste en una mezcla de patrones de diseño. Mencionaré solo los más importantes.
Modelo de controlador de vista de modelo
El patrón de diseño central (arquitectónico) que le gustaría usar es el patrón Modelo-Vista-Controlador . El Controlador debe estar representado por un Servlet que (in) crea / usa directamente un Modelo y Vista específicos basados en la solicitud. El modelo se representará mediante clases Javabean. Esto a menudo es más divisible en el Modelo de Negocio que contiene las acciones (comportamiento) y el Modelo de Datos que contiene los datos (información). La vista se representará con archivos JSP que tengan acceso directo al modelo ( datos ) mediante EL (lenguaje de expresión).
Luego, hay variaciones basadas en cómo se manejan las acciones y los eventos. Los populares son:
MVC basado en solicitud (acción) : este es el más sencillo de implementar. El modelo ( comercial ) trabaja directamente con y objetos. Debe reunir, convertir y validar los parámetros de solicitud (principalmente) usted mismo. La Vista se puede representar mediante HTML / CSS / JS simple y no mantiene el estado en todas las solicitudes. Así es como funciona Spring MVC , Struts and Stripes , entre otros .
HttpServletRequest
HttpServletResponse
MVC basado en componentes : esto es más difícil de implementar. Pero terminas con un modelo y una vista más simples en los que toda la API de Servlet "en bruto" se abstrae completamente. No debería tener la necesidad de reunir, convertir y validar los parámetros de solicitud usted mismo. El controlador realiza esta tarea y establece los parámetros de solicitud recopilados, convertidos y validados en el modelo . Todo lo que necesita hacer es definir métodos de acción que funcionen directamente con las propiedades del modelo. La Vista está representada por "componentes" en forma de taglibs JSP o elementos XML que a su vez generan HTML / CSS / JS. El estado de la vistapara las solicitudes posteriores se mantiene en la sesión. Esto es particularmente útil para la conversión del lado del servidor, la validación y los eventos de cambio de valor. ¡Así es como, entre otros , JSF , Wicket y Play! trabajos.
Como nota al margen, pasatiempo con un marco MVC de cosecha propia es un ejercicio de aprendizaje muy agradable, y lo recomiendo siempre que lo conserve para fines personales / privados. Pero una vez que sea profesional, se recomienda encarecidamente elegir un marco existente en lugar de reinventar el suyo. Aprender un marco existente y bien desarrollado requiere a largo plazo menos tiempo que desarrollar y mantener un marco robusto usted mismo.
En la explicación detallada a continuación, me limitaré a solicitar MVC basado, ya que es más fácil de implementar.
Patrón de controlador frontal ( patrón de mediador )
Primero, la parte Controlador debe implementar el patrón Controlador frontal (que es un tipo especializado de patrón Mediador ). Debe consistir en un solo servlet que proporcione un punto de entrada centralizado para todas las solicitudes. Debe crear el Modelo en función de la información disponible por la solicitud, como la información de ruta o la ruta de servlet, el método y / o parámetros específicos. El modelo de negocio se llama
Action
en el siguienteHttpServlet
ejemplo.La ejecución de la acción debería devolver algún identificador para ubicar la vista. Lo más sencillo sería usarlo como nombre de archivo del JSP. Asigne este servlet en un específico
url-pattern
enweb.xml
, por ejemplo/pages/*
,*.do
o incluso simplemente*.html
.En el caso de patrones de prefijos como, por ejemplo
/pages/*
, puede invocar URL como http://example.com/pages/register , http://example.com/pages/login , etc. y proporcionar/WEB-INF/register.jsp
,/WEB-INF/login.jsp
con las acciones GET y POST apropiadas . Las partesregister
,login
etc. están disponiblesrequest.getPathInfo()
como en el ejemplo anterior.Cuando utiliza patrones de sufijos como
*.do
,*.html
etc., puede invocar URL como http://example.com/register.do , http://example.com/login.do , etc. y debe cambiar el ejemplos de código en esta respuesta (también elActionFactory
) para extraer las partesregister
ylogin
en surequest.getServletPath()
lugar.Patrón de estrategia
El
Action
debe seguir el patrón de estrategia . Debe definirse como un tipo abstracto / interfaz que debe hacer el trabajo basado en los argumentos pasados del método abstracto (esta es la diferencia con el patrón de Comando , en el que el tipo abstracto / interfaz debe hacer el trabajo basado en el argumentos que se han pasado durante la creación de la implementación).Es posible que desee hacer el
Exception
más específico con una excepción personalizada comoActionException
. Es solo un ejemplo básico de inicio, el resto depende de usted.Aquí hay un ejemplo de un
LoginAction
que (como su nombre lo indica) inicia sesión en el usuario. ElUser
mismo es a su vez un modelo de datos . La Vista es consciente de la presencia deUser
.Patrón de método de fábrica
El
ActionFactory
debe seguir el patrón del método de fábrica . Básicamente, debe proporcionar un método de creación que devuelva una implementación concreta de un tipo abstracto / interfaz. En este caso, debería devolver una implementación de laAction
interfaz basada en la información proporcionada por la solicitud. Por ejemplo, el método y la información de ruta (la información de ruta es la parte posterior al contexto y la ruta de servlet en la URL de solicitud, excluyendo la cadena de consulta).A
actions
su vez, debe ser algo estático / en toda la aplicaciónMap<String, Action>
que contenga todas las acciones conocidas. Depende de usted cómo llenar este mapa. Código difícil:O configurable en función de un archivo de configuración de propiedades / XML en el classpath: (pseudo)
O basado dinámicamente en un escaneo en el classpath para clases que implementan una determinada interfaz y / o anotación: (pseudo)
Recuerde crear un "no hacer nada"
Action
para el caso de que no haya mapeo. Deje que, por ejemplo, devuelva directamente elrequest.getPathInfo().substring(1)
entonces.Otros patrones
Esos fueron los patrones importantes hasta ahora.
Para ir un paso más allá, puede usar el patrón Fachada para crear una
Context
clase que, a su vez, envuelva los objetos de solicitud y respuesta y ofrezca varios métodos convenientes para delegar en los objetos de solicitud y respuesta y pasar eso como argumento alAction#execute()
método. Esto agrega una capa abstracta adicional para ocultar la API de Servlet sin procesar. Básicamente, debería terminar con ceroimport javax.servlet.*
declaraciones en cadaAction
implementación. En términos de JSF, esto es lo que están haciendo las clasesFacesContext
yExternalContext
. Puedes encontrar un ejemplo concreto en esta respuesta .Luego está el patrón de Estado para el caso en el que desea agregar una capa de abstracción adicional para dividir las tareas de recopilar los parámetros de solicitud, convertirlos, validarlos, actualizar los valores del modelo y ejecutar las acciones. En términos de JSF, esto es lo que
LifeCycle
está haciendo.Luego está el patrón compuesto para el caso en el que desea crear una vista basada en componentes que se puede adjuntar con el modelo y cuyo comportamiento depende del estado del ciclo de vida basado en la solicitud. En términos de JSF, esto es lo que
UIComponent
representan.De esta manera, puede evolucionar poco a poco hacia un marco basado en componentes.
Ver también:
fuente
web.xml
, entonces podría usar unServletContextListener
para esto. Haga que la fábrica lo implemente (y se registre como<listener>
enweb.xml
) y haga el trabajo de llenado durante elcontextInitialized()
método.Action
implementación de la misma manera que con los servlets normales (vea también la wiki de servlets para un ejemplo básico, que puede refactorizar aún más en algunaValidator
interfaz). Pero también puede hacerlo antes de invocar la acción, pero esto es más complejo ya que requiere que las reglas de validación se conozcan por vista. JSF ha cubierto por esta ofertarequired="true"
,validator="customValidatorName"
, etc en el código XHTML.En el patrón MVC golpeado, el Servlet es "C" - controlador.
Su trabajo principal es hacer una evaluación de solicitud inicial y luego enviar el procesamiento basado en la evaluación inicial al trabajador específico. Una de las responsabilidades del trabajador puede ser configurar algunos beans de capa de presentación y reenviar la solicitud a la página JSP para representar HTML. Entonces, solo por esta razón, debe pasar el objeto de solicitud a la capa de servicio.
Sin embargo, no comenzaría a escribir
Servlet
clases crudas . El trabajo que hacen es muy predecible y repetitivo, algo que el marco hace muy bien. Afortunadamente, hay muchos candidatos disponibles y probados (en orden alfabético): Apache Wicket , Java Server Faces , Spring , por nombrar algunos.fuente
En mi humilde opinión, no hay mucha diferencia en el caso de la aplicación web si lo miras desde el ángulo de la asignación de responsabilidad. Sin embargo, mantenga la claridad en la capa. Guarde cualquier cosa exclusivamente para el propósito de la presentación en la capa de presentación, como el control y el código específico de los controles web. Simplemente mantenga sus entidades en la capa empresarial y todas las características (como agregar, editar, eliminar), etc. en la capa empresarial. Sin embargo, presentarlos en el navegador para ser manejados en la capa de presentación. Para .Net, el patrón ASP.NET MVC es muy bueno en términos de mantener las capas separadas. Mira en el patrón MVC.
fuente
He utilizado el marco de struts y me resulta bastante fácil de aprender. Cuando utilice el marco de struts, cada página de su sitio tendrá los siguientes elementos.
1) Se llama a una acción que se utiliza cada vez que se actualiza la página HTML. La acción debe llenar los datos en el formulario cuando la página se carga por primera vez y maneja las interacciones entre la interfaz de usuario web y la capa empresarial. Si está utilizando la página jsp para modificar un objeto Java mutable, se debe almacenar una copia del objeto Java en el formulario en lugar del original para que los datos originales no se modifiquen a menos que el usuario guarde la página.
2) El formulario que se utiliza para transferir datos entre la acción y la página jsp. Este objeto debe constar de un conjunto de captadores y definidores de atributos que deben ser accesibles para el archivo jsp. El formulario también tiene un método para validar los datos antes de que persistan.
3) Una página jsp que se usa para representar el HTML final de la página. La página jsp es un híbrido de HTML y etiquetas de struts especiales que se utilizan para acceder y manipular datos en el formulario. Aunque Struts permite a los usuarios insertar código Java en archivos jsp, debe tener mucho cuidado al hacerlo porque hace que su código sea más difícil de leer. El código Java dentro de los archivos jsp es difícil de depurar y no se puede probar en la unidad. Si se encuentra escribiendo más de 4-5 líneas de código java dentro de un archivo jsp, el código probablemente debería moverse a la acción.
fuente
La excelente respuesta de BalusC cubre la mayoría de los patrones para aplicaciones web.
Algunas aplicaciones pueden requerir un patrón de cadena de responsabilidad
Caso de uso para usar este patrón:
Cuando se desconoce el controlador para procesar una solicitud (comando) y esta solicitud se puede enviar a varios objetos. Generalmente establece sucesor para objetar. Si el objeto actual no puede manejar la solicitud o procesar la solicitud parcialmente y reenviar la misma solicitud al objeto sucesor .
Preguntas / artículos útiles sobre SE:
¿Por qué usaría una cadena de responsabilidad sobre un decorador?
Usos comunes para la cadena de responsabilidad?
patrón de cadena de responsabilidad de oodesign
cadena_de_responsabilidad de la creación de código fuente
fuente