table-module/README.md
The Table Module pattern expertly encapsulates database table data access logic in a single, efficient module, ideal for Java applications.
Real-world example
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
The Table Module pattern centralizes and encapsulates database access logic for a specific table, simplifying data retrieval and manipulation while hiding database complexities.
Flowchart
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.
@Setter
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor
public class User {
private int id;
private String username;
private String password;
}
Here is the UserTableModule class.
public class UserTableModule {
private final DataSource dataSource;
private Connection connection = null;
private ResultSet resultSet = null;
private PreparedStatement preparedStatement = null;
public UserTableModule(final DataSource userDataSource) {
this.dataSource = userDataSource;
}
public int login(final String username, final String password) throws SQLException {
// Method implementation
}
public int registerUser(final User user) throws SQLException {
// Method implementation
}
}
In the class App, we use an instance of the UserTableModule to handle user login and registration.
@Slf4j
public final class App {
private static final String DB_URL = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
private App() {}
public static void main(final String[] args) throws SQLException {
// Create data source and create the user table.
final var dataSource = createDataSource();
createSchema(dataSource);
var userTableModule = new UserTableModule(dataSource);
// Initialize two users.
var user1 = new User(1, "123456", "123456");
var user2 = new User(2, "test", "password");
// Login and register using the instance of userTableModule.
userTableModule.registerUser(user1);
userTableModule.login(user1.getUsername(), user1.getPassword());
userTableModule.login(user2.getUsername(), user2.getPassword());
userTableModule.registerUser(user2);
userTableModule.login(user2.getUsername(), user2.getPassword());
deleteSchema(dataSource);
}
private static void deleteSchema(final DataSource dataSource)
throws SQLException {
try (var connection = dataSource.getConnection();
var statement = connection.createStatement()) {
statement.execute(UserTableModule.DELETE_SCHEMA_SQL);
}
}
private static void createSchema(final DataSource dataSource)
throws SQLException {
try (var connection = dataSource.getConnection();
var statement = connection.createStatement()) {
statement.execute(UserTableModule.CREATE_SCHEMA_SQL);
}
}
private static DataSource createDataSource() {
var dataSource = new JdbcDataSource();
dataSource.setURL(DB_URL);
return dataSource;
}
}
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.
UserTableModule is initialized with a DataSource object which is used to establish a connection to the database.registerUser method in UserTableModule handles the logic for registering a new user into the database.login method manages the logic for authenticating a user based on their username and password.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.The program output:
13:59:36.417 [main] INFO com.iluwatar.tablemodule.UserTableModule -- Register successfully!
13:59:36.426 [main] INFO com.iluwatar.tablemodule.UserTableModule -- Login successfully!
13:59:36.426 [main] INFO com.iluwatar.tablemodule.UserTableModule -- Fail to login!
13:59:36.426 [main] INFO com.iluwatar.tablemodule.UserTableModule -- Register successfully!
13:59:36.427 [main] INFO com.iluwatar.tablemodule.UserTableModule -- Login successfully!
This example shows how the Table Module pattern centralizes database operations for the users table, making the application more modular and easier to maintain.
Benefits:
Trade-offs: