UML Class Diagrams: Types of Class Relationships
In object-oriented design, classes interact through various relationships. These relationships define how objects communicate and depend on each other within a system.
1. Association
Association represents a "uses-a" relationship where objects know about each other. It includes:
- Unidirectional Association: One class knows about another, but not vice versa.
- Bidirectional Association: Both classes are aware of each other.
- Self-Association: A class associates with itself (e.g., an employee managing other employees).
- Multiplicity: Defines cardinality (1:1, 1:N, N:M).
- Aggregation: A weak "has-a" relationship where the child can exist independently.
- Composition: A strong "has-a" relationship where the child cannot exist without the parent.
2. Generalization (Inheritance)
Represents an "is-a" relationship where a subclass inherits attributes and methods from a parent class.
3. Dependency
A relationship where one class depends on another, typically as a method parameter or local variable. Changes to the supplier may affect the client.
Single Responsibility Principle: Login Module Implementation
The Single Responsibility Principle (SRP) states that a class should have only one reason to change. A login module can be refactored to separate concerns: database operations, user interface, and authentication logic.
DatabaseConnection.java
package authentication.module;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DatabaseConnection {
private static final String DB_URL = "jdbc:mysql://localhost:3306/app_db?serverTimezone=UTC&useSSL=false";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "password";
private DatabaseConnection() {}
public static Connection establishConnection() {
Connection connection = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
} catch (ClassNotFoundException | SQLException e) {
System.err.println("Database connection failed: " + e.getMessage());
}
return connection;
}
public static void terminateConnection(ResultSet resultSet, Statement statement, Connection connection) {
closeResultSet(resultSet);
closeStatement(statement);
closeConnection(connection);
}
private static void closeResultSet(ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
System.err.println("Failed to close ResultSet: " + e.getMessage());
}
}
}
private static void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
System.err.println("Failed to close Statement: " + e.getMessage());
}
}
}
private static void closeConnection(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
System.err.println("Failed to close Connection: " + e.getMessage());
}
}
}
}
UserRepository.java
package authentication.module;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class UserRepository {
public boolean authenticateUser(String userId, String userPassword) {
String query = "SELECT password FROM users WHERE username = '" + userId + "'";
Connection connection = DatabaseConnection.establishConnection();
Statement statement = null;
ResultSet resultSet = null;
try {
statement = connection.createStatement();
resultSet = statement.executeQuery(query);
if (resultSet.next()) {
String storedPassword = resultSet.getString("password");
return userPassword.equals(storedPassword);
}
return false;
} catch (SQLException e) {
System.err.println("Authentication query failed: " + e.getMessage());
return false;
} finally {
DatabaseConnection.terminateConnection(resultSet, statement, connection);
}
}
}
LoginView.java
package authentication.module;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginView extends JFrame {
private JTextField userIdField;
private JPasswordField passwordField;
private UserRepository userRepository;
public LoginView() {
this.userRepository = new UserRepository();
initializeComponents();
configureLayout();
}
private void initializeComponents() {
setTitle("User Authentication");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
setSize(450, 250);
}
private void configureLayout() {
JPanel panel = new JPanel();
panel.setLayout(null);
JLabel userLabel = new JLabel("Username:");
userLabel.setBounds(50, 50, 80, 25);
panel.add(userLabel);
userIdField = new JTextField();
userIdField.setBounds(140, 50, 200, 25);
panel.add(userIdField);
JLabel passwordLabel = new JLabel("Password:");
passwordLabel.setBounds(50, 100, 80, 25);
panel.add(passwordLabel);
passwordField = new JPasswordField();
passwordField.setBounds(140, 100, 200, 25);
panel.add(passwordField);
JButton loginButton = new JButton("Sign In");
loginButton.setBounds(100, 160, 100, 30);
loginButton.addActionListener(new LoginActionListener());
panel.add(loginButton);
JButton resetButton = new JButton("Clear");
resetButton.setBounds(220, 160, 100, 30);
resetButton.addActionListener(e -> resetFields());
panel.add(resetButton);
add(panel);
setVisible(true);
}
private void resetFields() {
userIdField.setText("");
passwordField.setText("");
}
private class LoginActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String username = userIdField.getText().trim();
String password = new String(passwordField.getPassword()).trim();
if (username.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(null, "All fields are required", "Validation Error", JOptionPane.WARNING_MESSAGE);
return;
}
boolean isAuthenticated = userRepository.authenticateUser(username, password);
if (isAuthenticated) {
JOptionPane.showMessageDialog(null, "Authentication successful!", "Success", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null, "Invalid credentials", "Authentication Failed", JOptionPane.ERROR_MESSAGE);
}
}
}
}
Application.java
package authentication.module;
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(LoginView::new);
}
}
The refactored design separates responsibilities into three distinct classes:
- DatabaseConnection: Manages database connectivity and resource cleanup.
- UserRepository: Handles data access and authentication queries.
- LoginView: Manages the user interface and user interactions.