Next Article in Journal
Simple Modeling and Analysis of Total Ionizing Dose Effects on Radio-Frequency Low-Noise Amplifiers
Previous Article in Journal
Towards Building a Faster and Incentive Enabled Privacy-Preserving Proof of Location Scheme from GTOTP
Previous Article in Special Issue
Statement-Grained Hierarchy Enhanced Code Summarization
 
 
Font Type:
Arial Georgia Verdana
Font Size:
Aa Aa Aa
Line Spacing:
Column Width:
Background:
Article

Assessing System Quality Changes during Software Evolution: The Impact of Design Patterns Explored via Dependency Analysis

Department of Computer Science, National Taichung University of Education, Taichung 403514, Taiwan
*
Author to whom correspondence should be addressed.
Electronics 2024, 13(8), 1444; https://doi.org/10.3390/electronics13081444
Submission received: 31 January 2024 / Revised: 6 April 2024 / Accepted: 8 April 2024 / Published: 11 April 2024
(This article belongs to the Special Issue Advances in Software Engineering and Programming Languages)

Abstract

:
Design patterns provide solutions to recurring problems in software design and development, promoting scalability, readability, and maintainability. While past research focused on the utilization of the design patterns and performance, there is limited insight into their impact on program evolution. Dependency signifies relationships between program elements, reflecting a program’s structure and interaction. High dependencies indicate complexity and potential flaws, hampering system quality and maintenance. This paper presents how design patterns influence software evolution by analyzing dependencies using the Abstract Syntax Tree (AST) to examine dependency patterns during evolution. We employed three widely adopted design patterns from the Gang of Four (GoF) as experimental examples. The results show that design patterns effectively reduce dependencies, lowering system complexity and enhancing quality.

1. Introduction

Design patterns offer significant advantages in software development and have become essential standards for high-quality software design. Software engineers widely adopt them to enhance flexibility, reusability, and maintainability [1,2]. Current research mainly delves into pattern selection and implementation and their impact on systems [3,4,5]. Despite the extensive research on the impact of design patterns on software evolution, there remains a notable research gap in understanding the comprehensive influence of various design patterns on real-world software systems. Existing studies often focus on a limited set of design patterns within specific system versions, neglecting the broader spectrum of design patterns and their effects on long-term software evolution.
Dependency relationships represent the associations, interactions, and behaviors among program elements within a software system [6,7,8]. An evaluation of the impact and utility of design patterns in software systems often considers how design patterns influence dependency relationships, as such effects may have implications for software quality metrics such as complexity, maintainability, and scalability [9,10].
A total of 804 studies published between 2000 and 2018 were examined by Wedyan et al. [11]. The statistical analysis determined that the Factory Pattern, Decorator Pattern, and Observer Pattern are the most commonly used design patterns in three categories: Creational Pattern, Structural Pattern, and Behavioral Pattern. McNatt et al. [12] also mentioned that the Factory Pattern and Observer Pattern are the most frequently referenced design patterns. Similarly, Prechelt et al. [13] conducted research focusing on the Factory Pattern, Observer Pattern, and Decorator Pattern. Therefore, in this study, our attention was directed toward these three widely acknowledged design patterns sourced from the Gang of Four (GoF) [14]: the Factory Pattern, Decorator Pattern, and Observer Pattern. We designed individual experiments for each of the selected design patterns. To present the results generated by these design patterns in the experiments, we chose 39 dependency relationships from the 56 proposed by Huang [7] that are commonly associated with the three selected design patterns. By observing the variations in these dependency relationships in the experiment, the influence of these design patterns on different experimental environments can be determined. Additionally, we created a computational tool with Java Parser [15] to assist in minimizing the interference of the experimental environment during the calculation of dependency relationships. The assistance tool scans example programs employing the specified design patterns and those that do not and identifies code dependency relationships. Furthermore, our investigation included simulations of alterations in dependency relationships during program evolution. This allowed us to illustrate how design patterns can effectively diminish dependencies that arise throughout the evolution of a system, ultimately leading to the optimization of the software system.
In the following sections, we explore background knowledge (Section 2), detail our methodology for identifying dependency relationships (Section 3), present and discuss experimental results (Section 4), and conclude by outlining contributions and future research plans (Section 5).

2. Background Knowledge and Related Work

This section introduces the background knowledge and research context for this study, categorized into three subsections: Design Patterns, Dependency Relationships, and Abstract Syntax Trees (ASTs).

2.1. Design Patterns

Design patterns [14] are crucial principles in software engineering, providing reusable solutions to common design problems. They offer a structured approach to tackling typical design challenges in software development and bring various advantages to the process. Beyond resolving issues in system design, design patterns contribute to enhancing key software quality metrics, including readability, reusability, extensibility, maintainability, cohesion, and coupling [1,16,17].
Nanthaamornphong et al. [1] conducted a statistical survey on the Visitor Pattern, demonstrating that the complexity of software design was effectively reduced through the Visitor Pattern. Tahvildari et al. [16] found that utilizing design patterns in the system can enhance software system maintainability, whether creational, structural, or behavioral. In addition, Ampatzoglou et al. [17] revealed that, while incorporating GoF design patterns into a system may increase system size (including lines of code and the number of classes), all identified GoF design patterns improved system cohesion, reduced coupling, and decreased complexity. However, Khomh et al. [4] argued that not all design patterns are advantageous to system quality and may even reduce system extensibility or readability.
The Factory Pattern is a creational design pattern that defines an interface for creating objects in a superclass. However, it allows subclasses to modify the type of objects to be created. This pattern encourages loose coupling by removing the necessity to bind application-specific classes into the code directly. The Decorator Pattern is a structural design pattern that enables the addition of behavior to an individual object, either statically or dynamically, without impacting the behavior of other objects within the same class. This is accomplished by creating a series of decorator classes to encapsulate concrete components. The Observer Pattern is a behavioral design pattern in which an object, referred to as the subject, manages a list of dependents, known as observers, who should be informed of changes to the subject’s state. It establishes a one-to-many dependency between objects, ensuring that all its dependents are notified when one object changes its state. In this study, the experiment focused on the Factory Pattern, Decorator Pattern, and Observer Pattern, the results of which will be presented in Section 4.

2.2. Dependency Relationships

Dependency relationships describe interactions between program elements, such as package names, field names, types, etc. These elements are nodes in the program. Bichsel [6] classified 28 types of dependencies into method relationships and structural relationships. Method relationships explain the semantic behavior of methods. For instance, in the method call field.foo().bar(), two receiver-type dependencies emerge: (foo, bar, receiver) and (field, foo, receiver). Structural relationships capture connections between nodes. For example, the study introduced “read-before” and “written-before” relationships to depict the order of reading or writing fields. Huang [7] increased the number of dependency relationships to 56 and classified them into three types based on object-oriented concepts: encapsulation, abstraction, and delegation.
Encapsulation is a method to protect data from unauthorized access and modification by bundling data and methods in the program into a single unit. In addition to making programs easier to maintain and extend, encapsulation provides a clean and user-friendly interface due to its ability to hide details. When there are more encapsulation dependency relationships in the program, it typically means that not only is the structure of the program more closed and independent, but unit testing and refactoring are also easier to perform, making the program easier to maintain, extend, and understand. However, excessive encapsulation dependency relationships may lead to a high degree of coupling in the program, making it more difficult to modify and extend. If all parts of the program depend on each other, changing one part may require changing other parts simultaneously. This kind of dependency relationship may not only lead to the program design becoming more complex but also increase the difficulty of maintenance.
Abstraction is the process of hiding complexity, focusing on key details, and simplifying the functionality of the object or system into interfaces. It is usually used to hide details, making the program easier to maintain and extend. When there are more abstraction dependency relationships, it typically means that the program has a higher level of abstraction and lower dependency. Because the program can be easily changed with little effect on others, it may be easier to maintain and extend. However, excessive abstraction dependency relationships may lead to an unduly high level of abstraction in the program, not only making the program difficult to understand and maintain but also making the dependency relationships hard to manage.
Delegation is the process of distributing and entrusting work from one object to another. When a proxy object needs to provide a specific work, it entrusts the work to another rather than implementing it by itself. This typically means that the structure of the program becomes more complex when there are lots of delegation dependency relationships in the program. Because each object needs to be understood and managed, a large number of objects that depend on each other may require more maintenance and testing. Furthermore, multiple layers of delegation may also lead to reduced execution efficiency because each object needs to process and transmit information. However, because it makes the implementation of proxy objects easy to replace with other objects, programs can be made easier to extend and modify by using delegation appropriately. Moreover, delegation can also separate different works, making the program more modular and readable.
In this paper, we have selected 39 dependency relationships for our experiment. These selected dependencies are re-categorized into three types, encapsulation, abstraction, and delegation, forming the basis of our research. When analyzing the quality of software systems, dependency relationships are often considered as one of the factors [9,10]. In [9], Iyapparaja et al. mention that dependency relationships influence the complexity of the program. The more complex the interactions within a system, the harder the readability of specific designs, leading to a higher likelihood of faults and making testing more difficult. Dependency relationships are also utilized in research on software system refactoring. Maruyama et al. [18] proposed a mechanism for automating the refactoring of object-oriented frameworks through a weighted dependency relationship graph. Experiments demonstrated that the number of statements developers need to write when creating multiple applications can be reduced by up to 22 percent.

2.3. Abstract Syntax Tree (AST)

An Abstract Syntax Tree (AST) is an abstract representation used to describe the syntactic structure of code. It is a data structure employed by Java parsers to parse code into a format that is easier to understand and manipulate. ASTs represent the syntax of a programming language in a tree-like structure composed of nodes and edges. Each node represents an element in the code, such as a variable, operator, function call, and so on. Each node may also have additional attributes like values or child nodes to store the specific content or related sub-elements of that element. Edges denote the relationships between these elements, such as the parent–child relationships between nodes. The construction of an AST is implemented through the syntax analysis process, commonly known as parsing. A Java parser takes the source code and parses it into a series of syntactic units, such as tokens or abstract syntax units. It then uses these syntactic units to build the AST [19]. During the syntax analysis process, the code is validated according to the syntax rules of the programming language, and the corresponding AST structure is generated.
The AST can be used for syntax checking, error detection, code transformation, and more. For example, compilers can traverse the AST and perform various analyses and transformation operations, while parsers can use the AST to understand and perform a syntax analysis of program code. Developers can also utilize the AST for tasks like code refactoring and static code analysis [20]. Fauzi et al. [21] employed the AST to transform source code into sequence diagrams through reverse engineering. In [22], Tao et al. proposed a code plagiarism detection algorithm based on the AST. These examples demonstrate the versatility and utility of ASTs in various software engineering tasks.

3. Methodology

This section outlines our research methodology, structured into two parts: identifying dependency relationships and designing experimental procedures. The first part introduces dependency relationships related to design patterns and the computational tools developed to discover these relationships. Once the relationships are defined, the second part outlines the experimental procedure tailored to these relationships.

3.1. Identifying the Dependency Relationships

To assess software quality, this study evaluated dependency relationships in a software system. The upcoming subsection will detail the process of identifying these relationships.

3.1.1. Dependency Relationships Related to Design Patterns

This research specifically focuses on programs within the same package and design pattern. Therefore, certain types of dependency relationships are excluded: ‘contained-in-package’, ‘direct-subpackage-of’, ‘subpackage-of’, ‘innerClass-of’, ‘inner-type’, ‘performs-cast’, ‘instance-of’, and ‘use-known’. Additionally, dependencies related to the Android System, such as ‘indirect-invocation’, ‘intent’, ‘register-receiver’, and ‘filter’, will not be discussed. Furthermore, we categorized the dependency relationships with similar characteristics for the organization, such as ‘modifier’, ‘access-attribute’, and ‘self-delegation’. As a result, out of the 56 dependency relationships proposed by Huang [7], 39 relationships were selected in this research, as illustrated in Figure 1 (Dependency relationships with underlines indicate that they were excluded from this research). These chosen dependencies will be categorized into encapsulation, abstraction, and delegation.

3.1.2. Dependency Relationship Calculation Tool

In order to calculate dependency relationships in the system, we developed a calculation tool using the API provided by JavaParser [15]. This tool is capable of not only parsing Java source code but also generating the Abstract Syntax Tree (AST). This AST is analyzed to identify whether the program contains the aforementioned 39 types of dependency relationships and calculate their quantity. Next, the following is elucidated through illustrative examples. In terms of the system architecture of this assistance tool, as shown in Figure 2, the AST of this program is generated by first passing the source code to Logic Positivizer. Next, the AST is passed separately to Encapsulation Finder, Abstraction Finder, and Delegation Finder for scanning. Finally, the number of dependency relationships for encapsulation, abstraction, and delegation types can be obtained.
We elucidate the calculation method for each type of dependency relationship through mathematical expressions in Table 1, and the signification of the constituent elements within these mathematical formulations is shown in Table 2. Field-in in Table 2, for example, means all the fields declared in the package. By utilizing the mathematical expressions mentioned above within the tool, various dependencies within the code can be effectively identified, making subsequent experiments more convenient.

3.2. Design Experiment Steps

In order to investigate the relationship between design patterns and software quality, we designed the following experimental procedure. It is divided into four steps, as shown in Figure 3. The first step involves designing a sample program written without the use of design patterns. In the second step, a new sample program is designed by applying design patterns to refactor the initial program from step one. Step three simulates the evolution of both sample programs. In step four, the analysis tool is employed to scan the program to identify the number of dependency relationships in the code.
Take the Decorator Pattern as an example. The program for the experiment implements a pizza-ordering system, as shown in Figure 4. First, an initial design without the use of design patterns is created, as shown in Figure 4a. In step two, the initial code is refactored using the Decorator design pattern, as shown in Figure 4b. Step three simulates the evolution of both programs, as shown in Figure 4c,d. Finally, the dependency relationship calculation tool is used to scan and calculate the number of dependency relationships in these programs for comparison.
This study performed calculations for three types of dependency relationships: encapsulation, abstraction, and delegation. The total number of dependency relationships for each type is identified, as well as the average number of these contained in each class within the program. The results are presented as line charts in the next section.

4. Experiment and Results

This experiment focused on the aforementioned three types of design patterns: Factory Pattern, Decorator Pattern, and Observer Pattern. The purpose of this experiment was to compare the changes in dependency relationships within a program containing these design patterns with the changes in the program without these design patterns.

4.1. Factory Pattern

For the experiment with the Factory Pattern, this study designed a simple beverage store system as an example, with its program design illustrated in Figure 5. Figure 5a represents the initial design of the system, with a BeverageStore offering both GreenTea and BlackTea. With the continual addition of beverage items, this design requires frequent changes in the BeverageStore class to incorporate code for new items. The demand for frequent changes in program elements can be achieved by refactoring with the Factory Pattern, as shown in Figure 5b. Because of the abstraction of beverages through the use of the class SimpleBeverageFactory and the interface IBeverageProvider, it becomes unnecessary to modify the existing BeverageStores’s code when adding new beverage items. Two continuous versions of the BeverageStore system are represented in Figure 5c,d.
The following section presents our experimental results for the dependency relationships (encapsulation, abstraction, and delegation) in the Factory Pattern.

4.1.1. Encapsulation Dependency Relationships in Factory Pattern

The total number of encapsulation dependency relationships is shown in Table 3, and the average number of encapsulation dependency relationships within each class in the program is displayed in Table 4. By visualizing the experimental results as line charts, it can be observed that, though using the Factory Pattern leads to more encapsulation dependency relationships in the early stages of development, as the program evolves into later stages, the Factory Pattern continues to effectively reduce the number of these relationships and results in lower system complexity. The line representing the Factory Pattern is color-coded in red, as shown in Figure 6 and Figure 7.

4.1.2. Abstraction Dependency Relationships in Factory Pattern

The total number of abstraction dependency relationships is shown in Table 5, and the average number of abstraction dependency relationships within each class in the program is displayed in Table 6. Although the use of the Factory Pattern generates additional abstraction dependency relationships, the number of these dependency relationships still remains within a reasonable range, as shown in Figure 8 and Figure 9. Furthermore, based on the easy modification of its details without causing significant impacts on other parts, moderate abstraction can make the program easier to maintain and extend.

4.1.3. Delegation Dependency Relationships in Factory Pattern

The total number of delegation dependency relationships is shown in Table 7, and the average number of abstraction dependency relationships within each class in the program is displayed in Table 8. By visualizing the experimental results as line charts, it can be observed that a significant increase in delegation dependency relationships is caused in the program by not using the Factory Pattern, as shown in Figure 10 and Figure 11. Moreover, excessive delegation dependency relationships may lead to higher program coupling, making modifications and extensions more challenging.

4.2. Decorator Pattern

For the experiment involving the Decorator Pattern, this study designed a pizza-ordering system calculating the corresponding price based on the selected topping as an example, with its program design illustrated previously in Figure 4a. There are two toppings available, Cheese and Egg, which results in four different combinations and their corresponding prices: Classic, Cheese, Egg, or Cheese and Egg. However, when the restaurant decides to add a third topping, the number of available combinations to choose from will increase significantly, leading to an overly large and excessively complex system, as shown in Figure 4c. This issue can be improved by using the Decorator Pattern. Treating various toppings as different decorators can prevent the proliferation of numerous classes during the initial program evolution, as shown in Figure 4b,d.
The following section presents our experimental results for the dependency relationships (encapsulation, abstraction, and delegation) in the Decorator Pattern.

4.2.1. Encapsulation Dependency Relationships in Decorator Pattern

The total number of encapsulation dependency relationships is shown in Table 9, and the average number of encapsulation dependency relationships within each class in the program is displayed in Table 10. By visualizing the experimental results as line charts, it can be observed that the number of encapsulation dependency relationships in the program that does not contain the Decorator Pattern is significantly higher than that in the one with the Decorator Pattern, as shown in Figure 12 and Figure 13. As mentioned in Section 3.1.1, an excessive number of encapsulation dependency relationships leads to high program complexity, making modifications and extensions challenging.

4.2.2. Abstraction Dependency Relationships in Decorator Pattern

The total number of abstraction dependency relationships is shown in Table 11, and the average number of abstraction dependency relationships within each class in the program is displayed in Table 12. By visualizing the experimental results as line charts, it can be observed that the number of abstraction dependency relationships in the program that does not contain the Decorator Pattern is significantly higher than that in the one with the Decorator Pattern, as shown in Figure 14 and Figure 15. As mentioned in Section 3.1.1, high levels of abstraction dependency relationships make program maintenance and management challenging.

4.2.3. Delegation Dependency Relationships in Decorator Pattern

The total number of delegation dependency relationships is shown in Table 13, and the average number of abstraction dependency relationships within each class in the program is displayed in Table 14. Although programs using the Decorator Pattern have more delegation dependency relationships, their number still remains within a reasonable range, as shown in Figure 16 and Figure 17. As mentioned in Section 3.1.1, moderate delegation can make the program easier to evolve and modify while also enhancing modularity and readability.

4.3. Observer Pattern

For the experiment involving the Observer Pattern, this study designed a simple subscription notification system as an example, with its program design illustrated in Figure 18. When the Youtuber class updates its status, the Subscriber class will be notified, as shown in Figure 18a. However, the Youtuber class and Subscriber class are highly coupled in this design, and the Youtuber must know which Subscribers it has in order to notify them. Furthermore, as the number of Subscribers increases, the program will also become overly large.
This issue can be improved by using the Observer Pattern. The Youtuber can notify all Subscribers without needing to know the details of individual Subscribers through the interfaces IYoutuber and ISubscriber. Additionally, when adding new Subscribers, there is no need for repeated modifications to the existing program, as shown in Figure 18b. Finally, we depict the scenarios before and after system evolution following the refactoring in Figure 18c,d.
The following section presents our experimental results for the dependency relationships (encapsulation, abstraction, and delegation) in the Observer Pattern.

4.3.1. Encapsulation Dependency Relationships in Observer Pattern

The total number of encapsulation dependency relationships is shown in Table 15, and the average number of encapsulation dependency relationships within each class in the program is displayed in Table 16. By visualizing the experimental results as line charts, it can be observed that as the program extends into subsequent stages, using the Observer Pattern allows the refactored program to have a lower number of encapsulation dependency relationships compared to the initial program. It exhibits better performance in terms of system complexity, as shown in Figure 19 and Figure 20.

4.3.2. Abstraction Dependency Relationships in Observer Pattern

The total number of abstraction dependency relationships is shown in Table 17, and the average number of abstraction dependency relationships within each class in the program is displayed in Table 18. By visualizing the experimental results as line charts, it can be observed that appropriately elevating the program’s abstraction level not only reduces the dependence on the program but also makes it easier to extend and maintain, as shown in Figure 21 and Figure 22.

4.3.3. Delegation Dependency Relationships in Observer Pattern

The total number of delegation dependency relationships is shown in Table 19, and the average number of abstraction dependency relationships within each class in the program is displayed in Table 20. Although the use of the Observer Pattern may result in more delegation dependency relationships during the early stages of system development, as its evolution progresses, these dependency relationships are still reduced compared to the beginning, as shown in Figure 23 and Figure 24. This method can not only maintain the program’s structure but also enhance its maintainability and scalability.

4.4. Threats to Validity

This research opted to examine only a restricted set of design patterns in the experiment and analyzed the results based on a subset of dependency relationships. Expanding the scope of the experiment would bolster the assertions. Furthermore, it is essential to select high-quality studies from the literature as references for the experimental sample programs and tools to yield more comprehensive results. In summary, there is still ample room for improvement regarding both credibility and comprehensiveness in this study.

5. Conclusions

The purpose of this study was to analyze the impact of design patterns on system quality during software system evolution. We employed dependency relationships as a gauge of program complexity. By designing a tool to compute the number of these dependency relationships, it became possible to analyze the changes in these dependencies throughout the evolution process. The evaluation of the three frequently utilized design patterns proposed by the Gang of Four (GoF) as experimental examples led to the following conclusions.
Firstly, the use of design patterns effectively reduces the dependencies generated during system evolution. By introducing appropriate abstractions and decoupling mechanisms, design patterns help reduce direct inter-module dependencies, thereby reducing system complexity. This reduction in dependency has a positive impact by enhancing system scalability and readability, making the system more amenable to modifications and extensions.
Secondly, design patterns also have a positive impact on system quality. Through the judicious use of design patterns, the system’s structure becomes clearer and easier to understand, thus enhancing code readability. Furthermore, design patterns provide a generic solution that enables developers to more easily comprehend and design system architectures, thereby increasing system maintainability.
In summary, the results of this study indicate that design patterns play a significant role in software system evolution. By reducing dependencies and enhancing system quality, design patterns provide software developers with effective methods and guidelines to make systems more scalable, readable, and maintainable. In future research, it would be valuable to explore additional design patterns, conduct in-depth, real-world case studies, and develop refined methods for measuring dependencies, contributing to a more comprehensive understanding of the broader impact and benefits of diverse design patterns in software evolution.

Author Contributions

Conceptualization, K.-H.H.; Software, H.-C.S.-T.; Writing—review & editing, K.-H.H. and C.-H.T. All authors have read and agreed to the published version of the manuscript.

Funding

This research received no external funding.

Data Availability Statement

Data are contained within the article.

Conflicts of Interest

The authors declare no conflicts of interest.

References

  1. Nanthaamornphong, A.; Wetprasit, R. A controlled experiment: Do Visitor patterns improve design simplicity? In Proceedings of the 2014 8th Malaysian Software Engineering Conference (MySEC), Langkawi, Malaysia, 23–24 September 2014; pp. 90–95. [Google Scholar] [CrossRef]
  2. Pree, W. Design Patterns for Object-Oriented Software Development; ACM Press/Addison-Wesley Publishing Co.: Boston, MA, USA, 1995. [Google Scholar]
  3. Celikkan, U.; Bozoklar, D. A Consolidated Approach for Design Pattern Recommendation. In Proceedings of the 2019 4th International Conference on Computer Science and Engineering (UBMK), Samsun, Turkey, 11–15 September 2019; pp. 1–6. [Google Scholar] [CrossRef]
  4. Khomh, F.; Guéhéneuc, Y.G. Do Design Patterns Impact Software Quality Positively? In Proceedings of the 2008 12th European Conference on Software Maintenance and Reengineering, Athens, Greece, 1–4 April 2008; pp. 274–278. [Google Scholar] [CrossRef]
  5. Ampatzoglou, A.; Chatzigeorgiou, A.; Charalampidou, S.; Avgeriou, P. The Effect of GoF Design Patterns on Stability: A Case Study. IEEE Trans. Softw. Eng. 2015, 41, 781–802. [Google Scholar] [CrossRef]
  6. Bichsel, B.; Raychev, V.; Tsankov, P.; Vechev, M. Statistical Deobfuscation of Android Applications. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, Vienna, Austria, 24–28 October 2016; pp. 343–355. [Google Scholar] [CrossRef]
  7. Huang, S.W. Towards a Solution to IoT Interoperability through Reverse Engineering. Master’s Thesis, National Taiwan University, Taipei, Taiwan, 2017. [Google Scholar]
  8. Huang, H.Y. Atomic Services Generation from Java-Based Open Source Software. Master’s Thesis, National Taiwan University, Taipei, Taiwan, 2019. [Google Scholar]
  9. Iyapparaja, M.; Sureshkumar, S. Coupling and cohesion metrics in Java for adaptive reusability risk reduction. In Proceedings of the IET Chennai 3rd International Conference on Sustainable Energy and Intelligent Systems (SEISCON 2012), Tiruchengode, India, 27–29 December 2012. [Google Scholar] [CrossRef]
  10. Wand, A. Reuse Metrics and Assessment in Component-Based Development. In Proceedings of the 6th IASTED International Conference on Software Engineering and Applications, Cambridge, MA, USA, 4–6 November 2002; pp. 583–588. [Google Scholar]
  11. Wedyan, F.; Abufakher, S. Impact of design patterns on software quality: A systematic literature review. IET Softw. 2020, 14, 1–17. [Google Scholar] [CrossRef]
  12. McNatt, W.B.; Bieman, J.M. Coupling of design patterns: Common practices and their benefits. In Proceedings of the 25th Annual International Computer Software and Applications Conference, COMPSAC 2001, Chicago, IL, USA, 8–12 October 2001; pp. 574–579. [Google Scholar] [CrossRef]
  13. Prechelt, L.; Unger, B.; Tichy, W.F.; Brossler, P.; Votta, L.G. A controlled experiment in maintenance: Comparing design patterns to simpler solutions. IEEE Trans. Softw. Eng. 2001, 27, 1134–1144. [Google Scholar] [CrossRef]
  14. Gamma, E.; Helm, R.; Johnson, R.; Vlissides, J. Design Patterns: Elements of Reusable Object-Oriented Software; Addison-Wesley Longman Publishing Co., Inc.: Boston, MA, USA, 1995. [Google Scholar]
  15. van Bruggen Matozoid, D. javaparser. GitHub Repository. Retrieved from GitHub. Available online: https://github.com/javaparser/javaparser (accessed on 12 July 2023).
  16. Tahvildari, L.; Kontogiannis, K.; Mylopoulos, J. Quality-driven software re-engineering. J. Syst. Softw. 2003, 66, 225–239. [Google Scholar] [CrossRef]
  17. Ampatzoglou, A.; Chatzigeorgiou, A. Evaluation of object-oriented design patterns in game development. Inf. Softw. Technol. 2007, 49, 445–454. [Google Scholar] [CrossRef]
  18. Maruyama, K.; Shima, K.i. Automatic method refactoring using weighted dependence graphs. In Proceedings of the 21st International Conference on Software Engineering, Los Angeles, CA, USA, 16–22 May 1999; pp. 236–245. [Google Scholar] [CrossRef]
  19. Terrence, P. The Definitive ANTLR Reference; The Pragmatic Bookshelf: Raleigh, NC, USA, 2007. [Google Scholar]
  20. Fischer, G.; Lusiardi, J.; Von Gudenberg, J.W. Abstract Syntax Trees—and their Role in Model Driven Software Development. In Proceedings of the International Conference on Software Engineering Advances (ICSEA 2007), Cap Esterel, France, 25–31 August 2007; p. 38. [Google Scholar] [CrossRef]
  21. Fauzi, E.; Hendradjaya, B.; Sunindyo, W.D. Reverse engineering of source code to sequence diagram using abstract syntax tree. In Proceedings of the 2016 International Conference on Data and Software Engineering (ICoDSE), Denpasar, Indonesia, 26–27 October 2016; pp. 1–6. [Google Scholar] [CrossRef]
  22. Tao, G.; Guowei, D.; Hu, Q.; Baojiang, C. Improved Plagiarism Detection Algorithm Based on Abstract Syntax Tree. In Proceedings of the 2013 Fourth International Conference on Emerging Intelligent Data and Web Technologies, Xi’an, China, 9–11 September 2013; pp. 714–719. [Google Scholar] [CrossRef]
Figure 1. Categorization of dependency relationships.
Figure 1. Categorization of dependency relationships.
Electronics 13 01444 g001
Figure 2. System architecture.
Figure 2. System architecture.
Electronics 13 01444 g002
Figure 3. Experimental steps.
Figure 3. Experimental steps.
Electronics 13 01444 g003
Figure 4. Decorator program design.
Figure 4. Decorator program design.
Electronics 13 01444 g004
Figure 5. Factory program design.
Figure 5. Factory program design.
Electronics 13 01444 g005
Figure 6. Factory Pattern: total encapsulation dependencies.
Figure 6. Factory Pattern: total encapsulation dependencies.
Electronics 13 01444 g006
Figure 7. Factory Pattern: avg. encapsulation dependencies per class.
Figure 7. Factory Pattern: avg. encapsulation dependencies per class.
Electronics 13 01444 g007
Figure 8. Factory Pattern: total abstraction dependencies.
Figure 8. Factory Pattern: total abstraction dependencies.
Electronics 13 01444 g008
Figure 9. Factory Pattern: avg. abstraction dependencies per class.
Figure 9. Factory Pattern: avg. abstraction dependencies per class.
Electronics 13 01444 g009
Figure 10. Factory Pattern: total delegation dependencies.
Figure 10. Factory Pattern: total delegation dependencies.
Electronics 13 01444 g010
Figure 11. Factory Pattern: avg. delegation dependencies per class.
Figure 11. Factory Pattern: avg. delegation dependencies per class.
Electronics 13 01444 g011
Figure 12. Decorator Pattern: total encapsulation dependencies.
Figure 12. Decorator Pattern: total encapsulation dependencies.
Electronics 13 01444 g012
Figure 13. Decorator Pattern: avg. encapsulation dependencies per class.
Figure 13. Decorator Pattern: avg. encapsulation dependencies per class.
Electronics 13 01444 g013
Figure 14. Decorator Pattern: total abstraction dependencies.
Figure 14. Decorator Pattern: total abstraction dependencies.
Electronics 13 01444 g014
Figure 15. Decorator Pattern: avg. abstraction dependencies per class.
Figure 15. Decorator Pattern: avg. abstraction dependencies per class.
Electronics 13 01444 g015
Figure 16. Decorator Pattern: total delegation dependencies.
Figure 16. Decorator Pattern: total delegation dependencies.
Electronics 13 01444 g016
Figure 17. Decorator Pattern: avg. delegation dependencies per class.
Figure 17. Decorator Pattern: avg. delegation dependencies per class.
Electronics 13 01444 g017
Figure 18. Observer program design.
Figure 18. Observer program design.
Electronics 13 01444 g018
Figure 19. Observer Pattern: total encapsulation dependencies.
Figure 19. Observer Pattern: total encapsulation dependencies.
Electronics 13 01444 g019
Figure 20. Observer Pattern: avg. encapsulation dependencies per class.
Figure 20. Observer Pattern: avg. encapsulation dependencies per class.
Electronics 13 01444 g020
Figure 21. Observer Pattern: total abstraction dependencies.
Figure 21. Observer Pattern: total abstraction dependencies.
Electronics 13 01444 g021
Figure 22. Observer Pattern: avg. abstraction dependencies per class.
Figure 22. Observer Pattern: avg. abstraction dependencies per class.
Electronics 13 01444 g022
Figure 23. Observer Pattern: total delegation dependencies.
Figure 23. Observer Pattern: total delegation dependencies.
Electronics 13 01444 g023
Figure 24. Observer Pattern: avg. delegation dependencies per class.
Figure 24. Observer Pattern: avg. delegation dependencies per class.
Electronics 13 01444 g024
Table 1. The mathematical expressions of the dependency relationships.
Table 1. The mathematical expressions of the dependency relationships.
Encapsulation dependency relationshipsMathematical expression
f i e l d - i n | x | ,   x F D ,   x P ,   x   i s   d e c l a r e d   i n   P
m e t h o d - i n | x | ,   x M D ,   x P ,   x   i s   d e c l a r e d   i n   P
m o d i f i e r A = M D F D ,   | ( a ,   m ) | ,   m   i s   t h e   m o d i f i e r   o f   a ,   a A ,   b M
i n i t i a l i z e d - b y | ( a ,   b ) | ,   a t t r i b u t e   a   i s   i n i t i a l i z e d   i n   c l a s s   b ,   a A b ,   b C
g e t s A = A b M D F D ,   | ( a ,   b ) | ,   b   i s   a n   a t t r i b u t e   a s s i g n e d   w i t h   a ,   a A ,   b A b
r e a d - b e f o r e | ( a ,   b ) | ,   a   i s   a   f i e l d   w h i c h   i s   r e a d   b e f o r e   b   i n   t h e   s a m e   m e t h o d ,   a F D ,   b F D ,   a b
w r i t t e n - b e f o r e | ( a ,   b ) | ,   a   i s   a   f i e l d   w h i c h   i s   w r i t t e n   b e f o r e   b   i n   t h e   s a m e   m e t h o d ,   a F D ,   b F D ,   a b
f i e l d - t y p e | x | ,   x F D ,   x P ,   x   i s   d e c l a r e d   i n   P
p e r f o r m s - o p | x | ,   x o p ,   x C
r e t u r n s | ( a ,   b ) | ,   b   h a s   a   r e t u r n   v a l u e   a ,   a V b ,   b M
u s e s | ( a ,   b ) | ,   a   i s   u s e d   i n   b ,   a A ,   b M D
w r i t e s | ( a ,   b ) | ,   a   i s   w r i t t e n   i n   b ,   a F D ,   b M D
f l o w s - i n t o | ( a ,   b ) | ,   a   i s   a n   a r g u m e n t   o f   b ,   a V b ,   b M C D
l o o p - r e a d | x | ,   x A b M D C ,   x   i s   r e a d   i n   L ,   L C
l o o p - w r i t e | x | ,   x A b M D C ,   x   i s   r e a d   i n   L ,   L C
r e t u r n - t y p e | ( a ,   b ) | ,   b   h a s   a   r e t u r n   v a l u e   a ,   a V b ,   b M D
a r g t y p e -N | ( a ,   b ) | ,   a   i s   a n   a r g u m e n t   o f   b ,   a V b ,   b M D
e l e m e n t - t y p e | x | ,   x F D A r
e x p r e s s i o n - t y p e | x | ,   x F D V b
Abstraction dependency relationshipsMathematical expression
i m p l e m e n t | ( a ,   b ) | ,   b   i m p l e m e n t s   i n t e r f a c e   a ,   a I ,   b C ,   a b
e x t e n d s | ( a ,   b ) | ,   b   e x t e n d s   a ,   a C ,   b C ,   a b
o v e r r i d e s | ( A ,   B ) | ,   a   m e t h o d   i n   c l a s s   B   o v e r r i d e s   a   m e t h o d   i n   c l a s s   A ,   A C ,   B C ,   A B
o v e r r i d e - c o n c r e t e - m e t h o d | ( a ,   b ) | ,   m e t h o d   a   o v e r r i d e s   a   c o n c r e t e   m e t h o d   b ,   a M D ,   a C ,   b M D ,   b C
o v e r r i d e - a b s t r a c t - m e t h o d | ( a ,   b ) | ,   m e t h o d   a   o v e r r i d e s   a   a b s t r a c t   m e t h o d   b ,   a M D ,   a C ,   b M D ,   b C
o v e r l o a d s | ( A ,   B ) | ,   a   m e t h o d   i n   c l a s s   B   o v e r l o a d s   a   m e t h o d   i n   c l a s s   A ,   A C ,   B C ,   A B
o v e r l o a d - s t a t i c - m e t h o d | ( a ,   b ) | ,   m e t h o d   a   o v e r l o a d s   a   s t a t i c   m e t h o d   b ,   a M D ,   a C ,   b M D ,   b C
o v e r l o a d - n o n s t a t i c - m e t h o d | ( a ,   b ) | ,   m e t h o d   a   o v e r l o a d s   a   n o n s t a t i c   m e t h o d   b ,   a M D ,   a C ,   b M D ,   b C
Delegation dependency relationshipsMathematical expression
r e a d - c l a s s f i e l d | ( a ,   b ) | ,   m e t h o d   a   r e a d s   a   f i e l d   o f   c l a s s   b ,   a M D ,   b C
c a l l - c l a s s m e t h o d | ( a ,   b ) | ,   m e t h o d   a   c a l l s   a   m e t h o d   o f   c l a s s   b ,   a M D ,   b C
a c c e s s - a t t r i b u t e | ( a ,   b ) | ,   m e t h o d   a   a c c e s s e s   a   f i e l d   o f   c l a s s   b ,   a M D ,   b C
c r e a t i o n | ( a ,   b ) | ,   m e t h o d   a   c r e a t e s   a n   i n s t a n c e   o f   c l a s s   b ,   a M D ,   b C
e a g e r - c r e a t i o n | ( a ,   b ) | ,   f i e l d   a   c r e a t e s   a n   i n s t a n c e   o f   c l a s s   b ,   a F D ,   b C
o r d e r -N | ( a ,   b ) | ,   b   i s   a n   a r g u m e n t   o f   m e t h o d   a ,   a M D ,   b A r g ,   A r g = F D M D C
i n v o k e - n o n s t a t i c - m e t h o d | ( a ,   b ) | ,   n o n s t a t i c   m e t h o d   b   i s   c a l l e d   b y   m e t h o d   a ,   a M D ,   b M D C
i n v o k e - s t a t i c - m e t h o d | ( a ,   b ) | ,   s t a t i c   m e t h o d   b   i s   c a l l e d   b y   m e t h o d   a ,   a M D ,   b M D
i n v o k e - a b s t r a c t c - m e t h o d | ( a ,   b ) | ,   a b s t r a c t   m e t h o d   b   i s   c a l l e d   b y   m e t h o d   a ,   a M D ,   b M D
d e l e g a t i o n | ( a ,   b ) | ,   a n   o b j e c t   o f   c l a s s   a   f o r w a r d s   a n   o p e r a t i o n   t o   a n   o b j e c t   o f   c l a s s   b ,   a C ,   b C
s e l f - d e l e g a t i o n | ( a ,   a ) | ,   a n   o b j e c t   o f   c l a s s   a   f o r w a r d s   a n   o p e r a t i o n   t o   i t s e l f ,   a C
r e c e i v e r | ( a ,   b ) | ,   a   r e c e i v e s   i n f o r m a t i o n   f r o m   m e t h o d   b ,   a A ,   b M D ,   A = I t M D A b
Table 2. Terms and Explanations table.
Table 2. Terms and Explanations table.
TermDefinition
Package (P)the set of all program packages
Class (C)the set of all program classes
Field (FD)the set of all program fields across all classes
Method (MD)the set of all program methods across all classes
Attribute (Ab)the set of all attributes across all classes
Variable(Vb)the set of all variables in the program
Loop (L)the set of all loops in the program
MethodCall (MCD)the set of all method calls in the program
Static-Method (SMD)the set of all static methods across all classes
nonStatic-Method (nSMD)the set of all non-static methods across all classes
Modifier (M)the set of all modifiers in the program
Array (Ar)the set of all arrays in the program
Interfaces (I)the set of all program interfaces
Instance (It)the set of all instances in the program
Table 3. Total encapsulation dependencies in Factory Pattern.
Table 3. Total encapsulation dependencies in Factory Pattern.
Tea NumberInitial DesignFactory Pattern
22850
34261
45672
57083
68494
798105
8112116
9126127
10140138
11154149
12168160
13182171
14196182
15210193
Table 4. Avg. encapsulation dependencies per class in Factory Pattern.
Table 4. Avg. encapsulation dependencies per class in Factory Pattern.
Tea NumberInitial DesignFactory Pattern
29.33310
310.510.167
411.210.286
511.66710.375
61210.444
712.2510.5
812.44410.545
912.610.583
1012.72710.615
1112.83310.643
1212.92310.667
131310.688
1413.06710.706
1513.12510.722
Table 5. Total abstraction dependencies in Factory Pattern.
Table 5. Total abstraction dependencies in Factory Pattern.
Tea NumberInitial DesignFactory Pattern
202
303
404
505
606
707
808
909
10010
11011
12012
13013
14014
15015
Table 6. Avg. abstraction dependencies per class in Factory Pattern.
Table 6. Avg. abstraction dependencies per class in Factory Pattern.
Tea NumberInitial DesignFactory Pattern
200.4
300.5
400.571
500.625
600.667
700.7
800.727
900.75
1000.769
1100.786
1200.8
1300.813
1400.824
1500.833
Table 7. Total delegation dependencies in Factory Pattern.
Table 7. Total delegation dependencies in Factory Pattern.
Tea NumberInitial DesignFactory Pattern
2169
32410
43211
54012
64813
75614
86415
97216
108017
118818
129619
1310420
1411221
1512022
Table 8. Avg. delegation dependencies per class in Factory Pattern.
Table 8. Avg. delegation dependencies per class in Factory Pattern.
Tea NumberInitial DesignFactory Pattern
25.3331.8
361.667
46.41.571
56.6671.5
66.8571.444
771.4
87.1111.364
97.21.333
107.2721.308
117.3331.286
127.3851.267
137.4281.25
147.4671.235
157.51.222
Table 9. Total encapsulation dependencies in Decorator Pattern.
Table 9. Total encapsulation dependencies in Decorator Pattern.
Ingredient NumberInitial DesignDecorator Pattern
22019
33623
46827
513231
626035
751639
8102843
Table 10. Avg. encapsulation dependencies per class in Decorator Pattern.
Table 10. Avg. encapsulation dependencies per class in Decorator Pattern.
Ingredient NumberInitial DesignDecorator Pattern
243.8
343.833
443.857
543.875
643.889
743.9
843.909
Table 11. Total abstraction dependencies in Decorator Pattern.
Table 11. Total abstraction dependencies in Decorator Pattern.
Ingredient NumberInitial DesignDecorator Pattern
2126
3247
4488
5969
619210
738411
876812
Table 12. Avg. abstraction dependencies per class in Decorator Pattern.
Table 12. Avg. abstraction dependencies per class in Decorator Pattern.
Ingredient NumberInitial DesignDecorator Pattern
22.41.2
32.6671.167
42.8241.143
52.9091.125
62.9541.111
72.9771.1
82.9881.091
Table 13. Total delegation dependencies in Decorator Pattern.
Table 13. Total delegation dependencies in Decorator Pattern.
Ingredient NumberInitial DesignDecorator Pattern
204
306
408
5010
6012
7014
8016
Table 14. Avg. delegation dependencies per class in Decorator Pattern.
Table 14. Avg. delegation dependencies per class in Decorator Pattern.
Ingredient NumberInitial DesignDecorator Pattern
200.8
301
401.143
501.25
601.333
701.4
801.455
Table 15. Total encapsulation dependencies in Observer Pattern.
Table 15. Total encapsulation dependencies in Observer Pattern.
Subscriber NumberInitial DesignObserver Pattern
25060
36667
48274
59881
611488
713095
8146102
9162109
10178116
11194123
12210130
13226137
14242144
15258151
Table 16. Avg. encapsulation dependencies per class in Observer Pattern.
Table 16. Avg. encapsulation dependencies per class in Observer Pattern.
Subscriber NumberInitial DesignObserver Pattern
216.66712
316.511.167
416.410.571
516.33310.125
616.2869.778
716.259.5
816.2229.273
916.29.083
1016.1828.923
1116.1678.786
1216.1548.667
1316.1438.563
1416.1338.471
1516.1258.389
Table 17. Total abstraction dependencies in Observer Pattern.
Table 17. Total abstraction dependencies in Observer Pattern.
Subscriber NumberInitial DesignObserver Pattern
203
304
405
506
607
708
809
9010
10011
11012
12013
13014
14015
15016
Table 18. Avg. abstraction dependencies per class in Observer Pattern.
Table 18. Avg. abstraction dependencies per class in Observer Pattern.
Subscriber NumberInitial DesignObserver Pattern
200.6
300.667
400.714
500.75
600.778
700.8
800.818
900.833
1000.846
1100.857
1200.867
1300.875
1400.882
1500.889
Table 19. Total delegation dependencies in Observer Pattern.
Table 19. Total delegation dependencies in Observer Pattern.
Subscriber NumberInitial DesignObserver Pattern
21420
31922
42424
52926
63428
73930
84432
94934
105436
115938
126440
136942
147444
157946
Table 20. Avg. delegation dependencies per class in Observer Pattern.
Table 20. Avg. delegation dependencies per class in Observer Pattern.
Subscriber NumberInitial DesignObserver Pattern
24.6674
34.753.667
44.83.429
54.8333.25
64.8573.111
74.8753
84.8892.909
94.92.833
104.9092.769
114.9172.714
124.9232.667
134.9292.625
144.9332.588
154.9382.556
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Share and Cite

MDPI and ACS Style

Hsu, K.-H.; Szu-Tu, H.-C.; Tsai, C.-H. Assessing System Quality Changes during Software Evolution: The Impact of Design Patterns Explored via Dependency Analysis. Electronics 2024, 13, 1444. https://doi.org/10.3390/electronics13081444

AMA Style

Hsu K-H, Szu-Tu H-C, Tsai C-H. Assessing System Quality Changes during Software Evolution: The Impact of Design Patterns Explored via Dependency Analysis. Electronics. 2024; 13(8):1444. https://doi.org/10.3390/electronics13081444

Chicago/Turabian Style

Hsu, Kuo-Hsun, Hua-Chieh Szu-Tu, and Chia-Hsing Tsai. 2024. "Assessing System Quality Changes during Software Evolution: The Impact of Design Patterns Explored via Dependency Analysis" Electronics 13, no. 8: 1444. https://doi.org/10.3390/electronics13081444

Note that from the first issue of 2016, this journal uses article numbers instead of page numbers. See further details here.

Article Metrics

Back to TopTop