October 19, 2026
Impacts of using design patterns
Impactos do Uso de Padrões de Projeto
Thalia Vilela Ferreira; Vinicius Santos Andrade
DOI: 10.22167/2675-6528-202602378
Article derived from a Course Conclusion Work (TCC), with content based on the student’s original work and adapted to the editorial format of the E&S Magazine with the support of the ResumeAI tool, an artificial intelligence solution developed by Instituto Pecege for textual synthesis and organization.
Summary
Design patterns are successful solutions in various contexts that use object-oriented concepts to create flexible and reusable code. In software development, applying these solutions requires understanding their positive and negative impacts. Thus, the study aimed to evaluate these impacts by implementing the Composite, Factory Method, and Strategy design patterns, measuring their effects on complexity, coupling, and reuse with CK metrics. The methodology applied was quali-quantitative, with data obtained by applying the patterns to a software, measuring its state before and after, and observing the advantages and disadvantages resulting from the alteration. As a result, it was analyzed that complexity decreased, making the code simpler to work with and enabling greater reuse. The classes became more flexible and could adapt better to the extension of requirements, concluding that the use of patterns is recommended when gains in requirement complexity are achieved.
Keywords: Abstraction; Complexity; Flexibility; Objects; Relationship.
1. Introduction
The evolution of software programming marked a significant transition from monolithic approaches to more organized and modular structures. Initially, coding was performed in single blocks, with occasional conditional branches. Later, structured programming introduced code blocks such as conditionals, loops, and functions, fragmenting the logic into smaller parts. In the late 1960s, the object-oriented programming paradigm emerged, redefining system structuring (Eduardo Guerra, 2014).
An object-oriented system is composed of objects that interact to maintain an internal state and support specific operations, with the state being externally inaccessible. This paradigm involves the creation of classes and the establishment of relationships between them, defining the interaction of objects at runtime. Objects encapsulate data and actions, allowing them to be extended or modified independently, without altering other components (Ian Sommerville, 2010). The abstraction of concepts is fundamental to developing decoupled components, promoting greater software reuse and flexibility (Eduardo Guerra, 2014). The pillars of object orientation include inheritance, encapsulation, polymorphism, and abstraction. Inheritance allows a child class to acquire attributes and methods from a parent class, specializing its behavior. Encapsulation isolates logic and data, exposing only the necessary interface to the client. Polymorphism enables an object to take on the form of its abstractions, such as a superclass or interface (Eduardo Guerra, 2014).
The application of these object-oriented concepts led to the development of design patterns. Inspired by Christopher Alexander’s work on architectural patterns, it was realized that the same logic could be applied to software development. In 1994, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides cataloged these solutions in the book “Design Patterns: Elements of Reusable Object-Oriented Software” (Ian Sommerville, 2010). These patterns represent proven solutions to recurring problems, facilitating the creation of flexible and reusable code in various contexts.
However, the mere existence of a solution does not guarantee its effective application. When using design patterns in software development, it is essential to understand the positive and negative impacts that their implementation can generate. The choice of a pattern should be judicious, aligned with the requirements and specific context of the software, considering the advantages and disadvantages for informed decision-making. There is a practical gap in the in-depth understanding of how these patterns manifest in terms of software quality metrics, especially in contemporary development environments.
Given this scenario, the justification for this study lies in the need to provide an empirical evaluation of the impacts of applying design patterns. Understanding how the use of patterns such as Composite, Factory Method, and Strategy affects software coupling, complexity, reuse, and flexibility is crucial for developers. This work aims to evaluate the impact of using design patterns in software, with the advantages and disadvantages of their use in coupling, complexity, reuse, and especially flexibility, with the motivation of presenting them in the common context of web software development with the construction of REST APIs, frameworks, and database queries.
2. Material and Methods
The research conducted was characterized as exploratory, with the purpose of explicating the impact of using design patterns in software development. A quali-quantitative approach was adopted, combining the analysis of bibliographic information with the measurement of metrics in a practical case study, according to the methodology described below.
Initially, a comprehensive literature review was conducted to gather information on design patterns, including their intention, motivation, structure, benefits, and drawbacks. Additionally, knowledge was sought on methods to measure complexity and coupling in object-oriented applications. For this stage, established books and articles in the field were consulted, without restriction on publication date, given the stability of design pattern concepts over time (Gamma et al., 2008; Sommerville, 2010).
The empirical object of the study was a software developed specifically for an e-learning platform. The initial construction of the software was carried out without the application of design patterns, focusing only on minimal class separation. This initial state allowed for the establishment of baseline parameters for complexity and coupling, prior to the methodological intervention.
The project requirements were defined based on the author’s experience with e-learning platforms. They included course management, where a course is composed of modules with different content types, such as video, text, quiz, and audio, and the organization of courses into learning paths. A non-linear progression system was also considered, which releases modules based on the student’s performance in quizzes.
The software development was carried out using the Java programming language, version 17. The Spring framework, version 6.2.5, was employed in conjunction with Spring Boot, version 3.4.4, to facilitate development and dependency management. For database interaction, Spring Data MongoDB, version 3.4.4, was used, along with the Lombok library, version 1.18.36, for generating repetitive code.
The software architecture was organized in layers, dividing the classes into specific packages: `Api` for exposing REST endpoints, `client` for calls to external services (not implemented), `entity` for database entities, `enumeration` for fixed values, `repository` for database access, and `service` for business logic. The database used was MongoDB, version 7.0, running in a Docker container, version 4.28.0, with WSL 2.6.3.0 and Ubuntu 22.04.
Based on the analysis of the project code and requirements, the Factory Method, Composite, and Strategy design patterns were selected and implemented. The application of these patterns was carried out without further modifications to the code, aiming to isolate the direct impact of their introduction. The Factory Method pattern was applied for the parameterized creation of content objects, such as video, quiz, audio, and text, which are saved in the content collection and are part of the Content class.
The Composite pattern was used to treat simple and compound objects uniformly, specifically in querying a student’s activities, where tracks and courses were modeled to be treated similarly. The Strategy pattern was employed in the student progress functionality, to apply different algorithms based on quiz scores, allowing for dynamic behavior selection.
To measure software changes, the Chidamber and Kemerer (CK) metrics, proposed in 1994 with a focus on object orientation, were used. The metrics employed were: Weighted Methods per Class (WMC), to evaluate the complexity of each class; Depth of Inheritance Tree (DIT), to measure the number of levels in the inheritance tree; Number of Children (NOC), to quantify the subclasses of a class; Coupling Between Objects (CBO), to check the coupling between classes; and Response for a Class (RFC), to measure the number of methods that can be executed in response to a message (Sommerville, 2010).
Data collection occurred in two phases. Firstly, a measurement of CK metrics was performed on the software in its initial state, before the application of design patterns, using static analysis from the CK Metrics library added to the project. Secondly, after the implementation of the Factory Method, Composite, and Strategy patterns, a new measurement of the same metrics was carried out. The data analysis consisted of comparing the metric values obtained before and after the application of the patterns.
3. Results and Discussion
The application of design patterns in an e-learning software was evaluated with the objective of analyzing its impacts on quality metrics, such as complexity, coupling, reuse, and flexibility. The results obtained, through the application of the Composite, Factory Method, and Strategy patterns and measurement with the CK (Chidamber & Kemerer) metrics, revealed significant transformations in the code’s structure and behavior. The comparative analysis between the initial state of the software and its version after the implementation of the patterns allowed for the identification of practical advantages and disadvantages, aligning with the literature and providing an empirical basis for decision-making in development projects.
Bibliographic Survey
Design patterns, according to the literature, are established solutions that use the principles of object-orientation to develop flexible and reusable code. Each pattern is characterized by a name, a problem it seeks to solve, a structural solution, and the consequences of its application, which include advantages and disadvantages (Gamma et al, 2008). They are categorized into creational, structural, and behavioral, each addressing different aspects of object creation, organization, or interaction. The essence of these patterns lies in promoting flexibility, reusability, and decoupling, achieved through the use of abstractions, inheritance, and composition, which manifest in software through polymorphism (Gamma et al, 2008).
The Factory Method pattern, of the creational category, is used to delegate object creation to subclasses, allowing them to decide which object to instantiate. Its flexibility lies in the ability to implement any product abstraction and adapt the pattern’s structure to specific software requirements, always delegating the instantiation of concrete classes to their subclasses (Gamma et al, 2008). However, a notable disadvantage is the need to create a subclass of Creator for each instance of Product, which can increase complexity and compromise maintainability. Parameterizing creation by identifier can mitigate this issue, but may introduce excessive conditionals, reducing the decoupling between Factory and Product classes (Gamma et al, 2008).
The Composite pattern, structural in nature, is used to treat simple and composite objects uniformly, organizing them into a tree structure. A common interface allows both leaves (simple objects) and branches (compositions) to implement the same method, using polymorphism for consistent treatment (Gamma et al, 2008). Among its advantages, the reduction in application complexity stands out, as both types of objects are manipulated uniformly, reinforcing encapsulation. The simplicity of adding new subclasses is also a benefit. However, a disadvantage arises when requirements demand type restrictions, making it difficult to apply the pattern without the need for constant type checks (Gamma et al, 2008).
In turn, the Strategy pattern, a behavioral pattern, is applied when a main class needs to use several algorithms. These algorithms are encapsulated in separate classes that implement a common interface, allowing the behavior to be changed at runtime (Gamma et al, 2008). The main advantage is the ability to change algorithms independently, making them more understandable and flexible, as well as eliminating conditionals in the main class. On the other hand, its disadvantages include the creation of a large number of classes, which can increase the complexity of code reading, the need to handle null attributes, and the fact that the client needs to know the different strategies to select the correct one, which can decrease the coupling between them. Furthermore, some concrete classes may not use all the information received, leading to the maintenance of unnecessary data (Gamma et al, 2008).
The Chidamber and Kemerer (CK) metrics were used to quantify the impacts of applying the standards. WMC (Weighted Methods per Class) measures the complexity of a class by summing the complexities of its methods; high values indicate lower readability and reuse (Ian Sommerville, 2010). DIT (Depth of Inheritance Tree) indicates the number of levels in the inheritance tree; greater depth implies greater design complexity (Ian Sommerville, 2010). NOC (Number of Children) assesses the number of subclasses, with high values suggesting greater reuse, but also greater understanding complexity (Ian Sommerville, 2010). CBO (Coupling Between Objects) checks the coupling between classes; higher values indicate greater dependency (Ian Sommerville, 2010). Finally, RFC (Response For a Class) measures the number of methods that can be executed in response to a message; the higher, the more complex the class (Ian Sommerville, 2010).
Application of design patterns
In the functionality for querying a student’s activities, specifically in the `buscarCursosETrilhasPorAluno` method, the need to address the distinction between learning paths (trilhas) and courses was identified. A learning path is composed of courses, and its total workload is the sum of the workloads of the courses that comprise it, while a course has its own specific workload. Initially, the mapping to the `Aprendizado` class required that if the object was of type Course, the `módulos` attribute should be filled, and if it was of type Learning Path, the `cursos` attribute should be filled. This initial approach resulted in more complex and less flexible code due to the need for explicit differentiation and type conversion.
The application of the Composite pattern allowed treating Course and Track objects in a unified way, eliminating the need for the intermediate `Learning` class and type conversion methods. With this approach, the code became less complex and more flexible, as the manipulation of objects could be performed through a common interface. The use of Composite was specific to two abstractions and a single type of composition, which avoided excessive generalization. Furthermore, the project requirements did not impose type restrictions that could manifest the disadvantages of the pattern, such as the difficulty of restricting classes when only some types are allowed, as described in the literature.
For the student progression functionality, which involved releasing modules based on quiz performance, the Strategy pattern was applied. The performance processing logic, which generated different messages for each grade range (e.g., unlock the next module for grades above 80%), was divided among strategy classes. This division reduced conditional validations in the main class, making it less complex and easier to understand. Algorithms could be changed separately without affecting the main class, which increased system flexibility and allowed for the simple creation of new algorithms.
However, the application of the Strategy pattern also highlighted some of the disadvantages pointed out by the literature. It was observed that some strategy classes did not use all the information passed, such as the `module` object, which was transmitted to all strategies but used by only one of them. Furthermore, the implementation of the pattern required the creation of more code for the pattern’s structure than for the business rule itself. The client class, responsible for selecting the correct strategy, needed to maintain a list of references to all concrete strategy classes, which implies prior knowledge of the available strategies and an explicit dependency, reducing the decoupling between these classes.
The creation of content objects, such as video, quiz, audio, and text, was optimized with the application of the parameterized Factory Method pattern. Initially, the content creation method was complex, with conditionals for each media type. With the Factory Method, the Factory class was created to receive the content type and the necessary data, delegating the creation of the specific object to an appropriate constructor. This approach significantly simplified the creation method, making it more readable and less error-prone, as the instantiation logic was centralized and parameterized by type.
Despite the initial simplification, the application of the Factory Method revealed a potential disadvantage: the Factory class, although simpler, can become more complex as new content types are added to the project. Each new media type would require a new conditional in the Factory class, increasing its maintainability difficulty and internal complexity. This shows that, although the pattern solves the object creation problem, it can transfer complexity to the factory itself if not carefully designed to handle extensibility more dynamically, such as through a factory registry.
Comparison of Metrics
The analysis of CK metrics before and after applying the patterns revealed distinct impacts. Regarding WMC (Weighted Methods per Class), a decrease was observed in all cases: from 7 to 3 in Factory Method, from 10 to 9 in Composite, and from 4 to 2 in Strategy. This reduction indicates that the complexity of the classes decreased, making the code better distributed and, consequently, simpler to work with and with greater reuse potential. The decrease in WMC is a positive indicator of improvement in software readability and maintainability.
The DIT (Depth of Inheritance Tree) and NOC (Number of Children) indicators showed no significant changes in any of the pattern applications. For Factory Method, DIT remained at 1 and NOC at 0. For Composite, DIT remained at 1 and NOC at 0. Similarly, for Strategy, DIT and NOC remained unchanged at 1 and 0, respectively. This occurred because the evaluated classes did not have modifications related to inheritance or changes to their methods in a way that would impact these indicators, focusing simplification on internal logic and responsibility distribution.
The RFC (Response For a Class) metric showed variations. In the Factory Method pattern, there was a large decrease, from 32 to 14. This is due to the fact that the class started executing fewer methods directly, as object creation was delegated to the Factory. In Composite, the RFC had a slight increase, from 48 to 49, which is expected, as methods were added to generalize object handling. In the Strategy pattern, the RFC remained stable at 24, indicating that the number of methods that can be executed in response to a message has not changed significantly.
Regarding CBO (Coupling Between Objects), variations were also observed. In Factory Method, there was a gain in relation to coupling, with a decrease from 14 to 12. Although the dependency with the Factory class was added, the class started calling it only for object creation, avoiding the assembly of objects with setter methods, which reduced overall coupling. In Strategy, the CBO increased from 9 to 10, as the class started calling two more methods of the pattern’s interface, which represents an external dependency. For the Composite pattern, the CBO had a slight increase from 13 to 14, but the exact reason for this variation was not identified in the original study.
In summary, the application of design patterns demonstrated positive impacts on the software’s flexibility and scalability, facilitating the addition of new classes and maintenance. The research showed that patterns allow the creation of adaptable structures to solve specific problems, not being fixed solutions. The use of the Factory Method, for example, can simplify object creation, but requires attention to the complexity of the Factory class itself. The Composite pattern proved effective in creating structures that can be loaded with database data and manipulated recursively with polymorphism, with the advantage of being able to grow with the addition of more methods to the interface.
The patterns, by being based on the principles of inheritance, polymorphism, and abstraction of object-oriented programming, make the code more understandable after an analysis of its structure, requiring, however, prior knowledge of the proposed solution. Observed disadvantages include the increase in the number of classes and the need to evaluate whether the project requirements justify the additional complexity introduced by the patterns, or if simpler refactorings could achieve similar gains. The application of the Strategy pattern, for example, can be particularly beneficial when aligned with SOLID best practices, promoting the separation of responsibilities and flexibility in changing algorithms.
4. Conclusion
This study evaluated the impact of using the Composite, Factory Method, and Strategy design patterns in a software, seeking to understand their advantages and disadvantages in terms of coupling, complexity, reuse, and flexibility, with a focus on the context of web software development. It was found that the application of these patterns promoted a significant reduction in class complexity, as indicated by the decrease in WMC (Weighted Methods per Class) in all analyzed cases. The Composite pattern, by unifying the treatment of simple and composite objects, made the code more flexible and less complex, eliminating the need for intermediate classes. The Factory Method simplified object creation, centralizing instantiation logic and reducing RFC (Response For a Class) and CBO (Coupling Between Objects) in the client class. In turn, the Strategy pattern contributed to the reduction of conditional validations in the main class, increasing flexibility in algorithm alteration and making them more understandable. The DIT (Depth of Inheritance Tree) and NOC (Number of Children) indicators remained stable, suggesting that the modifications focused on internal logic and responsibility distribution, without altering the inheritance hierarchy.
The main contribution of this work lies in offering an empirical evaluation of the effects of design patterns on software quality metrics, providing practical subsidies for developers in decision-making regarding their application. It was observed that, although patterns bring gains in flexibility and expandability, they can introduce disadvantages, such as an increase in the number of classes or the transfer of complexity to the factory itself, in the case of Factory Method, or the need for the client to know the specific strategies, in the case of Strategy. Such limitations reinforce the importance of a careful analysis of project requirements to justify the additional complexity. It is suggested that future studies explore the application of these patterns in conjunction with refactoring techniques and SOLID best practices, in order to further optimize the separation of responsibilities and code maintainability, evaluating whether simpler refactorings could achieve similar gains in specific contexts.
Bibliographic References
GAMMA, E.; HELM, R.; JOHNSON, R.; VLISSIDES, J. Padrões de projeto: soluções reutilizáveis de software orientado a objetos. Porto Alegre: Bookman, 2008.
GUERRA, E. Design patterns com Java: projeto orientado a objetos guiado por padrões. São Paulo: Novatec, 2010.
SOMMERVILLE, I.; SIQUEIRA, F. Engenharia de software. São Paulo: Pearson, 2010.
Article originating from the Final Course Work of the Specialization in Software Engineering of the MBA USP/Esalq
To learn more about the course, click here and access the MBX Academy platform