From 16d8395c8150d28d590272d06b27cd960854b473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 22 May 2024 10:02:16 +0300 Subject: [PATCH] docs: update table module --- table-module/README.md | 93 ++++++++++++------- .../tablemodule/UserTableModuleTest.java | 4 +- .../com/iluwatar/tablemodule/UserTest.java | 3 +- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/table-module/README.md b/table-module/README.md index 9479753f7..0007ce758 100644 --- a/table-module/README.md +++ b/table-module/README.md @@ -1,27 +1,34 @@ --- title: Table Module -category: Structural +category: Data access language: en tag: - - Data access + - Data access + - Encapsulation + - Persistence --- +## Also known as + +* Record Set + ## Intent -Table Module organizes domain logic with one class per table in the database, and a single instance of a class contains the various procedures that will act on the data. + +Encapsulates database table data access logic in a single module, allowing for easy retrieval and manipulation of data without exposing the database structure. ## Explanation -Real world example +Real-world example -> When dealing with a user system, we need some operations on the user table. We can use the table module pattern in this scenario. We can create a class named UserTableModule and initialize a instance of that class to handle the business logic for all rows in the user table. +> Imagine a library where all books are stored in a large database. The Table Module design pattern can be compared to a librarian who manages a specific section of the library, such as the fiction section. This librarian is responsible for all tasks related to that section: adding new books, updating book information, removing old books, and providing information about the books when requested. Just like the Table Module pattern encapsulates all the database access logic for a particular table, the librarian handles all operations related to the fiction section without exposing the complexities of how books are cataloged, stored, and managed to the library users. This makes it easier for the library users to interact with the fiction section, as they can rely on the librarian to efficiently manage and retrieve books without needing to understand the underlying details. In plain words -> A single instance that handles the business logic for all rows in a database table or view. +> The Table Module pattern centralizes and encapsulates database access logic for a specific table, simplifying data retrieval and manipulation while hiding database complexities. -Programmatic Example +**Programmatic Example** -In the example of the user system, we need to deal with the domain logic of user login and user registration. We can use the table module pattern and create an instance of the class `UserTableModule` to handle the business logic for all rows in the user table. +In the user system example, the domain logic for user login and registration needs to be managed. By using the Table Module pattern, we can create an instance of the `UserTableModule` class to encapsulate and handle all business logic associated with the rows in the user table. Here is the basic `User` entity. @@ -51,28 +58,12 @@ public class UserTableModule { this.dataSource = userDataSource; } - /** - * Login using username and password. - * - * @param username the username of a user - * @param password the password of a user - * @return the execution result of the method - * @throws SQLException if any error - */ public int login(final String username, final String password) throws SQLException { - // Method implementation. - + // Method implementation } - /** - * Register a new user. - * - * @param user a user instance - * @return the execution result of the method - * @throws SQLException if any error - */ public int registerUser(final User user) throws SQLException { - // Method implementation. + // Method implementation } } ``` @@ -109,25 +100,57 @@ The program output: 12:22:13.144 [main] INFO com.iluwatar.tablemodule.UserTableModule - Login successfully! ``` +In this example, the `UserTableModule` class is responsible for encapsulating all interactions with the users table in the database. This includes the logic for logging in and registering users. The User class represents the user entity with attributes such as `id`, `username`, and `password`. + +1. **Initialization**: The `UserTableModule` is initialized with a `DataSource` object which is used to establish a connection to the database. +2. **User Registration**: The `registerUser` method in `UserTableModule` handles the logic for registering a new user into the database. +3. **User Login**: The `login` method manages the logic for authenticating a user based on their username and password. +4. **Application Flow**: The `App` class demonstrates how to use the `UserTableModule` to register and log in users. The data source is created, the schema is set up, and users are registered and logged in with appropriate feedback. + +This example shows how the Table Module pattern centralizes database operations for the `users` table, making the application more modular and easier to maintain. + ## Class diagram -![](./etc/table-module.urm.png "table module") +![Table Module](./etc/table-module.urm.png "Table Module") ## Applicability -Use the Table Module Pattern when +* Use when you need to manage data access logic for a database table in a centralized module. +* Ideal for applications that interact heavily with database tables and require encapsulation of database queries. +* Suitable for systems where the database schema may evolve over time, as the changes can be managed within the table module. -- Domain logic is simple and data is in tabular form. -- The application only uses a few shared common table-oriented data structures. +## Known Uses -## Related patterns +* In enterprise applications where multiple modules need to interact with the same database tables. +* Web applications that require CRUD operations on database tables. +* Java-based ORM frameworks such as Hibernate or JPA utilize similar concepts for managing data access. -- [Transaction Script](https://java-design-patterns.com/patterns/transaction-script/) +## Consequences -- [Domain Model](https://java-design-patterns.com/patterns/domain-model/) +Benefits: + +* Centralizes and encapsulates data access logic, leading to easier maintenance. +* Reduces code duplication by providing a single point of interaction for database tables. +* Enhances code readability and reduces the risk of SQL injection attacks by encapsulating query logic. + +Trade-offs: + +* May lead to a large module if the table has many operations, potentially reducing readability. +* Can become a bottleneck if not properly optimized, especially in high-load scenarios. + +## Related Patterns + +* Active Record: Unlike Table Module, Active Record combines data access and domain logic in the same class. +* Data Mapper: Separates the in-memory objects from the database, unlike Table Module which directly maps database tables. +* Repository: Abstracts the data layer, allowing more complex queries, whereas Table Module is usually simpler and table-centric. +* Transaction Script: Organizes business logic by procedures where each procedure handles a single request from the presentation layer, contrasting with the Table Module's data-centric approach. +* Data Access Object (DAO): Provides an abstract interface to some type of database or other persistence mechanism, often used alongside Table Module to separate low-level data access operations from high-level business logic. +* Domain Model: Represents the domain logic and behavior, often used in conjunction with Table Module to handle complex business rules and data interactions. ## Credits +* [Core J2EE Patterns: Best Practices and Design Strategies](https://amzn.to/4cAbDap) +* [Java Persistence with Hibernate](https://amzn.to/44tP1ox) +* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR) +* [Architecture patterns: Domain model and friends - Inviqa](https://inviqa.com/blog/architecture-patterns-domain-model-and-friends) * [Table Module Pattern](http://wiki3.cosc.canterbury.ac.nz/index.php/Table_module_pattern) -* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=18acc13ba60d66690009505577c45c04) -* [Architecture patterns: domain model and friends](https://inviqa.com/blog/architecture-patterns-domain-model-and-friends) \ No newline at end of file diff --git a/table-module/src/test/java/com/iluwatar/tablemodule/UserTableModuleTest.java b/table-module/src/test/java/com/iluwatar/tablemodule/UserTableModuleTest.java index f45c20176..f77067e6f 100644 --- a/table-module/src/test/java/com/iluwatar/tablemodule/UserTableModuleTest.java +++ b/table-module/src/test/java/com/iluwatar/tablemodule/UserTableModuleTest.java @@ -86,9 +86,7 @@ class UserTableModuleTest { var userTableModule = new UserTableModule(dataSource); var user = new User(1, "123456", "123456"); userTableModule.registerUser(user); - assertThrows(SQLException.class, () -> { - userTableModule.registerUser(user); - }); + assertThrows(SQLException.class, () -> userTableModule.registerUser(user)); } @Test diff --git a/table-module/src/test/java/com/iluwatar/tablemodule/UserTest.java b/table-module/src/test/java/com/iluwatar/tablemodule/UserTest.java index 458acabc6..51da1847c 100644 --- a/table-module/src/test/java/com/iluwatar/tablemodule/UserTest.java +++ b/table-module/src/test/java/com/iluwatar/tablemodule/UserTest.java @@ -45,7 +45,8 @@ class UserTest { @Test void testEquals1() { var user = new User(1, "janedoe", "iloveyou"); - assertNotEquals("42", user); + assertNotEquals(user, new User(123, "abcd", + "qwerty")); } @Test