-
Notifications
You must be signed in to change notification settings - Fork 1
Design Patterns
To complete this project we used 6 of the following Design Patterns.
The builder design pattern is employed for the construction of the different types of items and requests.The ItemBuilder class, which defines common parameters such as title, yearPublished, quantity, price, and ISBN. Concrete builders, like BookBuilder, DVDBuilder, and MagazineBuilder, extend the abstract builder, providing specialised methods for setting additional attributes specific to their respective item types, such as genre, author, and duration. These concrete builders implement the build() method to produce instances of their corresponding item types. Moreover, a dedicated BookRequestBuilder exists for constructing book request objects, setting attributes like email, title, author, ISBN, edition, and booktype. Through this pattern, clients can create items or requests by instantiating the appropriate builder, chaining method calls to specify desired attributes, and finally invoking the build() method to obtain the finalised object. By encapsulating the construction logic within dedicated builder classes, the pattern promotes a modular approach to object creation, allowing us to focus on setting specific attributes without being overwhelmed by constructor overloads or intricate instantiation.
The UserFactory class serves as the factory, containing a method getUser responsible for instantiating user objects. This method takes parameters such as email, password, name, type, and validation status to create user instances tailored to different user types, including students, faculty, non-faculty staff, managers, and visitors. By utilising the factory pattern, the system abstracts the user creation process, allowing for centralised control and decoupling of object instantiation from the client code. Moreover, any changes to the user creation process or the addition of new user types can be implemented within the factory class without affecting the rest of the codebase. This enhances scalability and facilitates adherence to the open/closed principle, as the system can be easily extended to accommodate future requirements or modifications in user types.
The decorator design pattern is a structural pattern used to enhance the behaviour of individual objects dynamically, without altering the behaviour of other objects within the same class. The decorator pattern is used to add additional responsibilities/roles to objects to extend the functionality of items in the library. The Item class, serving as the base component defining the fundamental functionalities common to all items. Concrete decorators, such as PurchasableItemDecorator and RentableItemDecorator, are implemented to provide specific enhancements to items by extending the ItemDecorator base class. The ItemDecorator class acts as a wrapper around Item objects, enabling the addition of new behaviours while maintaining compatibility with existing code. Concrete decorators override methods inherited from ItemDecorator to modify or augment the behaviour of the wrapped item. For instance, the PurchasableItemDecorator adds purchase functionality to an item, while the RentableItemDecorator enables the item to be rented. Some items may also be available to both rent and purchase which is allowed as decorators can be stacked on top of each other to provide cumulative functionality to each item they decorate. We can apply decorators to items as needed, dynamically enhancing their capabilities without the need for subclassing or modifying the base Item class.
The strategy pattern is used for the selection of algorithms for generating recommendations based on various criteria. The strategy class defines a common interface with the getRecommendation(String query) method, responsible for returning a list of recommended books based on the provided query. Concrete strategy classes, such as AuthorRecommendationStrategy, GenreRecommendationStrategy, and others, extend the Strategy class, each implementing a specific recommendation algorithm tailored to a distinct criterion, such as author, genre, publication year, publisher, or title. These concrete strategies override the getRecommendation method to execute their respective recommendation logic, utilising the query parameter to filter and retrieve relevant books from the library database accessed through the MaintainBooks class. This approach offers flexibility and extensibility, allowing for easy addition of new recommendation strategies without altering existing code.
The facade pattern is used to make different types of payment options available to the user. The design of the program needs the isValid and getMode methods to judge if a payment is valid and the mode exists. To use this, there is a common interface called PaymentValidator, that is implemented by all the modes, that are credit card, debit card, mobile wallet and paypal. So whenever a payment has to be done irrespective of the mode, we can use the instance of the interface and get the two required methods. This helps us with having clean code and it also promotes code reusability.
The singleton pattern is used in our database to ensure that only a single copy of the database exists at any given time. This is done by making the constructors private and using a getInstance method that returns the existing object, or creates one if not done so already. Doing this saves memory by not loading multiple instances of the large databases into memory. It also ensures that all facets of the program are always working with the same data as all references to the data are pointers to the same database object.