Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Patrones creacionales
Builder
Problema: La clase Invoice es compleja con una gran cantidad de parámetros en su constructor. Esto dificulta la creación de estos objetos y condiciona a tener todos los parámetros que necesita la clase antes de su creación.
Solución e implicaciones: Utilizando el patrón creacional Builder, se crea una interfaz genérica Builder que contenga el método build(). Esta interface será implementada por InvoiceBuilder, que permitirá crear objetos Invoice de manera dinámica y sin necesidad de tener todos los parámetros que requiere la clase al momento de su instalación.
Singleton
Problema: Employee es la clase que representa al empleado que está utilizando el programa, sea administrador o personal normal. Este empleado es único debido a que se crea durante el login después de que el usuario añade correctamente sus credenciales. Tener diferentes instancias del mismo Employee en toda la aplicación puede comprometer la integridad de los datos de Employee.
Solución e implicaciones: Mediante el patrón creacional Singleton, se busca tener una única instancia de la clase Employee en toda la aplicación. La solución más óptima consistió en crear una clase AppState que contenga el atributo de tipo Employee con sus respectivos getters y setters. Esta clase AppState es instanciada durante la inicialización de la aplicación en la clase MainApp.
La referencia de AppState se pasa a través de los controladores de la aplicación para que puedan tener acceso a la instancia. Se creó una interface Controller que todo controlador debe implementar y que tiene como método setAppState(), de manera que todo controlador acepte la referencia de AppState.
Factory Method
Problema: Product es una clase muy global que con el tiempo puede crecer y volverse difícil de mantener. Al extraer la funcionalidad no esencial hacia clases hijas, se crean clases derivadas de Product que vuelve difícil la creación de un producto según sus diferentes tipos.
Solución e implicaciones: Haciendo uso del patrón creacional Factory Method se buscó poder crear instancias de todo tipo de productos a través de la delegación de clases de fabrica o factorías. Estas clases de fábrica extienden de ProductFactory que representa la clase abstracta que dicta la creación de un producto genérico. Cada una de las diferentes factorías para cada tipo de producto específico extiende de esta clase ProductFactory y añade métodos y atributos adicionales en caso de necesitar para poder crear el respectivo producto.
Patrones estructurales
Adapter
Problema: Existe una relación de funcionalidad parcial entre las clases Product e Item, pero cada uno extiende de interfaces diferentes no compatibles. Para evitar el código repetido en algunas partes del proyecto, se busca que estas clases sean compatibles e interoperables.
Solución e implicaciones: Haciendo uso del patrón estructural Adapter, se crea una clase ItemAdapter para que un Ítem pueda obtener la funcionalidad de Product en caso de requerirse. En esta solución, ItemAdapter no implementa directamente a Product sino que extendió de ProductBase aprovechando que se había creado en la solución del patrón Builder. De esta manera, un ItemAdapter puede comportarse completamente como un Product recibiendo un Item.
Facade
Problema: Product es una clase que se presta a tener muchas instancias durante toda la aplicación, además de los diferentes tipos de clases hijas que posee. No existe en el proyecto una manera centralizada de manejar una colección de productos cuando se requiera hacer uso de estos, como al mostrar el inventario por ejemplo.
Solución e implicaciones: El patrón Facade nos permite reducir la complejidad del manejo de productos a través de una interfaz que podamos proveer al cliente. Por esta razón, se creó una interfaz ProductManager que representa la funcionalidad que implica el manejo de productos en la aplicación. La clase que utilizará el cliente para implementar esta funcionalidad será ProductManagerFacade.
Decorator
Problema: Existen características para Product que puede ser opcional o no en todos los casos requerirse. Se necesita implementar parte de esta funcionalidad sin que se tenga que modificar las clase Product por sí misma concretamente para añadir la posibilidad de que un producto tenga un descuento. Actualmente, descuento es una propiedad que se da en Invoice, pero no necesariamente un descuento aplica a toda una factura sino a productos específicos.
Solución e implicaciones: Esto se puede lograr haciendo uso de el patrón estructural Decorator. Se creó una clase abstracta ProductDecorator que implementa a Product pero que recibe una instancia de product en su constructor. De esta manera, se pueden crear todo tipo de decoradores para Product, no solo un descuento.
Se creo una clase Descuento que extienda de ProductDecorator. Descuento tiene la funcionalidad de Product pero añade el atributo descuento y modifica el precio para entregarlo con el descuento calculado. Ahora cuando se necesite calcular el precio de un producto que posee un descuento solo se necesita hacer uso de este decorador y llamar al método getPrice.