0% found this document useful (0 votes)
17 views

Design Patterns

Patterns

Uploaded by

baminiaishwarya
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

Design Patterns

Patterns

Uploaded by

baminiaishwarya
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

Design Patterns

● Design patterns are typical solutions to commonly occurring problems in software design. They are like pre-made
blueprints that you can customize to solve a recurring design problem in your code.
● You can’t just find a pattern and copy it into your program, the way you can with off-the-shelf functions or libraries. The
pattern is not a specific piece of code, but a general concept for solving a particular problem. You can follow the pattern
details and implement a solution that suits the realities of your own program.

Pattern vs algorithm
● Patterns are often confused with algorithms, because both concepts describe typical solutions to some known problems.
While an algorithm always defines a clear set of actions that can achieve some goal, a pattern is a more high-level
description of a solution. The code of the same pattern applied to two different programs may be different.
● An analogy to an algorithm is a cooking recipe: both have clear steps to achieve a goal. On the other hand, a pattern is
more like a blueprint: you can see what the result and its features are, but the exact order of implementation is up to
you.

Classification of Patterns

● Creational patterns provide object creation mechanisms that increase flexibility and reuse of existing code.
● Structural patterns explain how to assemble objects and classes into larger structures, while keeping these structures
flexible and efficient.
● Behavioral patterns take care of effective communication and the assignment of responsibilities between objects

Factory Design Pattern

The Factory Design Pattern is a creational pattern that provides an interface for creating objects in a superclass but allows
subclasses to alter the type of objects that will be created. It encapsulates the object creation logic and allows the client code
to use the same interface to create different types of objects without specifying their concrete classes.

Here's a simple explanation of how it works:


1. Interface: Define an interface or abstract class for creating objects.
2. Factory: Create a factory class that implements the interface or extends the abstract class. This factory class contains
the object creation logic.
3. Client: Use the factory class to create objects without knowing the specific class of the object being created.

+-------------------------------------+
| Task |
+-------------------------------------+
| - taskId: int |
| - taskName: String |
| - taskDescription: String |
+-------------------------------------+
| + Task(taskId: int, taskName: String, taskDescription: String) |
| + getTaskId(): int |
| + getTaskName(): String |
| + getTaskDescription(): String |
+-------------------------------------+
|
|
|
v
+-------------------------------------+
| TaskManager |
+-------------------------------------+
| + addTask(task: Task): void |
| + deleteTask(task: Task): void |
| + displayTaskDetails(task: Task): void |
+-------------------------------------+
^
|
|
+-------------------------------------+
| FileHandler |
+-------------------------------------+
| + readFile(filePath: String): void |
| + writeFile(filePath: String, task: Task): void |
+-------------------------------------+
^ ^
| |
+------------------+ +-----------------+
| TxtFileHandler | | JsonFileHandler |
+------------------+ +-----------------+
| | | |
+------------------+ +-----------------+

// Task.java
public class Task {
private int taskId;
private String taskName;
private String taskDescription;

public Task(int taskId, String taskName, String taskDescription) {


this.taskId = taskId;
this.taskName = taskName;
this.taskDescription = taskDescription;
}

// Getters and setters


}

// TaskManager.java
public interface TaskManager {
void addTask(Task task);
void deleteTask(Task task);
void displayTaskDetails(Task task);
}

// TxtFileHandler.java
public class TxtFileHandler implements FileHandler {
@Override
public void readFile(String filePath) {
// Implementation for reading from a .txt file
}

@Override
public void writeFile(String filePath, Task task) {
// Implementation for writing to a .txt file
}
}

// JsonFileHandler.java
public class JsonFileHandler implements FileHandler {
@Override
public void readFile(String filePath) {
// Implementation for reading from a .json file
}

@Override
public void writeFile(String filePath, Task task) {
// Implementation for writing to a .json file
}
}

// TaskManagerFactory.java
public class TaskManagerFactory {
public static TaskManager createTaskManager(String fileType) {
if ("txt".equalsIgnoreCase(fileType)) {
return new TaskManagerImpl(new TxtFileHandler());
} else if ("json".equalsIgnoreCase(fileType)) {
return new TaskManagerImpl(new JsonFileHandler());
} else {
throw new IllegalArgumentException("Invalid file type");
}
}
}

// TaskManagerImpl.java
public class TaskManagerImpl implements TaskManager {
private FileHandler fileHandler;

public TaskManagerImpl(FileHandler fileHandler) {


this.fileHandler = fileHandler;
}

@Override
public void addTask(Task task) {
// Implementation for adding a task
fileHandler.writeFile("tasks.txt", task);
}

@Override
public void deleteTask(Task task) {
// Implementation for deleting a task
}

@Override
public void displayTaskDetails(Task task) {
// Implementation for displaying task details
System.out.println("Task ID: " + task.getTaskId());
System.out.println("Task Name: " + task.getTaskName());
System.out.println("Task Description: " + task.getTaskDescription());
}
}

Adapter Design Pattern


The Adapter Design Pattern is a structural pattern that allows objects with incompatible interfaces to work together. It acts as a
bridge between two incompatible interfaces by converting the interface of a class into another interface that a client expects.
This pattern helps in reusing existing classes without modifying their code and promotes interoperability between different
systems.
In simple terms, the Adapter Design Pattern allows objects with different interfaces to work together seamlessly by providing a
wrapper that translates one interface to another.

Now, let's implement the Adapter Design Pattern in the context of the Task Manager example. Suppose we have an existing
FileReader class that reads tasks from a file, but its interface is different from what our TaskManager expects. We can
create an adapter class FileReaderAdapter that adapts the FileReader interface to the TaskManager interface.

// FileReader.java (Existing class with incompatible interface)


public class FileReader {
public List<Task> readTasksFromFile(String filePath) {
// Implementation for reading tasks from a file
return new ArrayList<Task>(); // Placeholder for demonstration
}
}

// TaskManager.java (Target interface)


public interface TaskManager {
void addTask(Task task);
void deleteTask(Task task);
void displayTaskDetails(Task task);
}

// FileReaderAdapter.java (Adapter class)


public class FileReaderAdapter implements TaskManager {
private FileReader fileReader;

public FileReaderAdapter(FileReader fileReader) {


this.fileReader = fileReader;
}

@Override
public void addTask(Task task) {
// Implementation for adding task using FileReader
List<Task> tasks = fileReader.readTasksFromFile("tasks.txt");
tasks.add(task);
// Save modified tasks back to the file (if necessary)
}

@Override
public void deleteTask(Task task) {
// Implementation for deleting task using FileReader
List<Task> tasks = fileReader.readTasksFromFile("tasks.txt");
tasks.remove(task);
// Save modified tasks back to the file (if necessary)
}

@Override
public void displayTaskDetails(Task task) {
// Implementation for displaying task details using FileReader
List<Task> tasks = fileReader.readTasksFromFile("tasks.txt");
// Display details of the specified task (if it exists in the file)
}
}

// Main.java (Client code)


public class Main {
public static void main(String[] args) {
FileReader fileReader = new FileReader();
TaskManager taskManager = new FileReaderAdapter(fileReader);

// Use TaskManager methods


Task task1 = new Task(1, "Task 1", "Description 1");
taskManager.addTask(task1);
taskManager.displayTaskDetails(task1);
taskManager.deleteTask(task1);
}
}

Proxy Design Pattern


The Proxy Design Pattern is a structural pattern that provides a surrogate or placeholder for another object to control access
to it. It acts as an intermediary between the client and the real object, allowing the proxy to add functionality such as lazy
initialization, access control, logging, or caching without changing the original object's code.
In simple terms, the Proxy Design Pattern allows us to create a representative object (proxy) that controls access to another
object (real subject) by providing an interface similar to the real subject and performing additional operations when needed.

We'll have a TaskManager interface representing the task management functionality, and a RealTaskManager class as
the real subject that performs actual task management operations. The TaskManagerProxy class will act as a proxy to
control access to the real task manager.

// TaskManager.java
public interface TaskManager {
void addTask(Task task);
void deleteTask(Task task);
void displayTaskDetails(Task task);
}

// RealTaskManager.java
public class RealTaskManager implements TaskManager {
@Override
public void addTask(Task task) {
System.out.println("Task added: " + task.getTaskName());
}

@Override
public void deleteTask(Task task) {
System.out.println("Task deleted: " + task.getTaskName());
}

@Override
public void displayTaskDetails(Task task) {
System.out.println("Task details: " + task.getTaskName());
}
}

// TaskManagerProxy.java
public class TaskManagerProxy implements TaskManager {
private RealTaskManager realTaskManager = new RealTaskManager();

@Override
public void addTask(Task task) {
// Additional logic can be added here (e.g., access control)
realTaskManager.addTask(task);
}

@Override
public void deleteTask(Task task) {
// Additional logic can be added here (e.g., logging)
realTaskManager.deleteTask(task);
}

@Override
public void displayTaskDetails(Task task) {
// Additional logic can be added here (e.g., caching)
realTaskManager.displayTaskDetails(task);
}
}
// Task.java
public class Task {
private int taskId;
private String taskName;
private String taskDescription;

public Task(int taskId, String taskName, String taskDescription) {


this.taskId = taskId;
this.taskName = taskName;
this.taskDescription = taskDescription;
}

public int getTaskId() {


return taskId;
}

public String getTaskName() {


return taskName;
}

public String getTaskDescription() {


return taskDescription;
}
}

// Main.java
public class Main {
public static void main(String[] args) {
TaskManager taskManager = new TaskManagerProxy();

Task task1 = new Task(1, "Task 1", "Description 1");


taskManager.addTask(task1);
taskManager.displayTaskDetails(task1);
taskManager.deleteTask(task1);
}
}

Bridge Design Pattern


The Bridge Design Pattern is a structural pattern that separates an abstraction from its implementation so that they can vary
independently. It allows the abstraction and implementation to be developed independently and the client code to access them
through a common interface.
In simpler terms, the Bridge pattern decouples the abstraction (e.g., an interface or abstract class) from its implementation,
allowing them to vary independently and enabling easier extension and modification.

Let's apply the Bridge Design Pattern to our Task Manager example. We'll have an abstraction TaskManager interface and
its implementation classes (PersonalTaskManager and WorkTaskManager). Additionally, we'll have a separate
implementation interface StorageProvider and its implementation classes (DatabaseStorageProvider and
FileStorageProvider). This way, the task management functionality (TaskManager) can be developed independently
from the storage mechanism (StorageProvider), and they can be combined flexibly.
// TaskManager.java (Abstraction interface)
public interface TaskManager {
void addTask(Task task);
void deleteTask(Task task);
void displayTaskDetails(Task task);
}

// PersonalTaskManager.java (Concrete implementation 1)


public class PersonalTaskManager implements TaskManager {
private StorageProvider storageProvider;

public PersonalTaskManager(StorageProvider storageProvider) {


this.storageProvider = storageProvider;
}

@Override
public void addTask(Task task) {
// Implementation specific to PersonalTaskManager
storageProvider.storeTask(task);
System.out.println("Personal task added: " + task.getTaskName());
}

// Other methods implemented similarly


}

// WorkTaskManager.java (Concrete implementation 2)


public class WorkTaskManager implements TaskManager {
private StorageProvider storageProvider;

public WorkTaskManager(StorageProvider storageProvider) {


this.storageProvider = storageProvider;
}

@Override
public void addTask(Task task) {
// Implementation specific to WorkTaskManager
storageProvider.storeTask(task);
System.out.println("Work task added: " + task.getTaskName());
}

// Other methods implemented similarly


}

// StorageProvider.java (Implementation interface)


public interface StorageProvider {
void storeTask(Task task);
void deleteTask(Task task);
Task retrieveTask(int taskId);
}

// DatabaseStorageProvider.java (Concrete implementation 1)


public class DatabaseStorageProvider implements StorageProvider {
@Override
public void storeTask(Task task) {
// Implementation specific to storing tasks in a database
}

// Other methods implemented similarly


}

// FileStorageProvider.java (Concrete implementation 2)


public class FileStorageProvider implements StorageProvider {
@Override
public void storeTask(Task task) {
// Implementation specific to storing tasks in a file
}

// Other methods implemented similarly


}

// Main.java (Client code)


public class Main {
public static void main(String[] args) {
StorageProvider databaseStorageProvider = new DatabaseStorageProvider();
TaskManager personalTaskManager = new PersonalTaskManager(databaseStorageProvi

Task task1 = new Task(1, "Personal Task 1", "Description 1");


personalTaskManager.addTask(task1);
personalTaskManager.displayTaskDetails(task1);
}
}

Chain of Responsibility Pattern

The Chain of Responsibility pattern is a behavioral design pattern that allows multiple objects to handle a request without the
sender needing to know which object will handle it. It creates a chain of objects, each of which has the ability to either handle
the request or pass it on to the next object in the chain.

In simpler terms, the Chain of Responsibility pattern decouples the sender of a request from its receiver, allowing multiple
objects to handle the request in a flexible and organized manner.

Let's apply the Chain of Responsibility pattern to our Task Manager example. We'll create a chain of handlers to process task-
related requests, such as adding, deleting, or displaying task details.

// Task.java
public class Task {
private int taskId;
private String taskName;
private String taskDescription;

public Task(int taskId, String taskName, String taskDescription) {


this.taskId = taskId;
this.taskName = taskName;
this.taskDescription = taskDescription;
}

// Getters and setters


}
// TaskHandler.java (Handler interface)
public interface TaskHandler {
void handleTask(Task task);
}

// AddTaskHandler.java (Concrete handler)


public class AddTaskHandler implements TaskHandler {
private TaskHandler nextHandler;

public AddTaskHandler(TaskHandler nextHandler) {


this.nextHandler = nextHandler;
}

@Override
public void handleTask(Task task) {
// Logic to handle adding task
System.out.println("Task added: " + task.getTaskName());

// Pass the task to the next handler in the chain


if (nextHandler != null) {
nextHandler.handleTask(task);
}
}
}

// DeleteTaskHandler.java (Concrete handler)


public class DeleteTaskHandler implements TaskHandler {
private TaskHandler nextHandler;

public DeleteTaskHandler(TaskHandler nextHandler) {


this.nextHandler = nextHandler;
}

@Override
public void handleTask(Task task) {
// Logic to handle deleting task
System.out.println("Task deleted: " + task.getTaskName());

// Pass the task to the next handler in the chain


if (nextHandler != null) {
nextHandler.handleTask(task);
}
}
}

// DisplayTaskDetailsHandler.java (Concrete handler)


public class DisplayTaskDetailsHandler implements TaskHandler {
@Override
public void handleTask(Task task) {
// Logic to handle displaying task details
System.out.println("Task details: " + task.getTaskName());
}
}
// TaskManager.java (Client)
public class TaskManager {
private TaskHandler taskHandlerChain;

public TaskManager() {
// Build the chain of responsibility
taskHandlerChain = new AddTaskHandler(new DeleteTaskHandler(new DisplayTaskDet
}

public void processTask(Task task) {


// Start the chain of responsibility
taskHandlerChain.handleTask(task);
}
}

// Main.java
public class Main {
public static void main(String[] args) {
TaskManager taskManager = new TaskManager();

Task task1 = new Task(1, "Task 1", "Description 1");


taskManager.processTask(task1);
}
}

Decorator Design Pattern


The Decorator Design Pattern is a structural pattern that allows behavior to be added to individual objects, either statically or
dynamically, without affecting the behavior of other objects from the same class. It is used to extend or alter the functionality of
objects at runtime by wrapping them in an object of a decorator class.

In simpler terms, the Decorator pattern allows us to add new functionality to an object without changing its structure. It
achieves this by creating a set of decorator classes that are used to wrap concrete components and add new behaviors.

Let's apply the Decorator Design Pattern to our Task Manager example. We'll have a base TaskManager interface
representing the core functionality, and we'll create concrete implementations of this interface. Then, we'll create decorator
classes that add additional functionalities, such as encryption or logging, to the task manager.

// TaskManager.java (Component interface)


public interface TaskManager {
void addTask(Task task);
void deleteTask(Task task);
void displayTaskDetails(Task task);
}

// BaseTaskManager.java (Concrete component)


public class BaseTaskManager implements TaskManager {
@Override
public void addTask(Task task) {
System.out.println("Task added: " + task.getTaskName());
}

@Override
public void deleteTask(Task task) {
System.out.println("Task deleted: " + task.getTaskName());
}

@Override
public void displayTaskDetails(Task task) {
System.out.println("Task details: " + task.getTaskName());
}
}

// TaskManagerDecorator.java (Decorator)
public abstract class TaskManagerDecorator implements TaskManager {
protected TaskManager taskManager;

public TaskManagerDecorator(TaskManager taskManager) {


this.taskManager = taskManager;
}

@Override
public void addTask(Task task) {
taskManager.addTask(task);
}

@Override
public void deleteTask(Task task) {
taskManager.deleteTask(task);
}

@Override
public void displayTaskDetails(Task task) {
taskManager.displayTaskDetails(task);
}
}

// EncryptionDecorator.java (Concrete decorator)


public class EncryptionDecorator extends TaskManagerDecorator {
public EncryptionDecorator(TaskManager taskManager) {
super(taskManager);
}

@Override
public void addTask(Task task) {
// Additional encryption logic
System.out.println("Encrypting task data...");
super.addTask(task);
}
}

// LoggingDecorator.java (Concrete decorator)


public class LoggingDecorator extends TaskManagerDecorator {
public LoggingDecorator(TaskManager taskManager) {
super(taskManager);
}

@Override
public void addTask(Task task) {
// Additional logging logic
System.out.println("Logging task addition...");
super.addTask(task);
}
}

// Main.java (Client code)


public class Main {
public static void main(String[] args) {
TaskManager baseTaskManager = new BaseTaskManager();
TaskManager encryptedTaskManager = new EncryptionDecorator(baseTaskManager);
TaskManager loggingTaskManager = new LoggingDecorator(baseTaskManager);

Task task1 = new Task(1, "Task 1", "Description 1");

// Task added with encryption


encryptedTaskManager.addTask(task1);

// Task added with logging


loggingTaskManager.addTask(task1);
}
}

Command Design Pattern

The Command Design Pattern is a behavioral design pattern that encapsulates a request as an object, thereby allowing
parameterization of clients with queues, requests, and operations. It allows the requester to be decoupled from the executor,
enabling parameterization of clients with queues, requests, and operations.

Imagine you have a remote control with different buttons, each representing a specific action. When you press a button, the
remote control sends a command to execute that action. The remote control doesn't need to know how the action is
performed; it only knows the command to execute.

Let's apply the Command Design Pattern to our Task Manager example. We'll define a Command interface representing a
task-related operation, and concrete implementations of this interface for different actions such as adding, deleting, or
displaying task details.

In our Task Manager example:

● Each command (AddTaskCommand, DeleteTaskCommand, etc.) represents a specific task-related action.


● The TaskManagerInvoker acts like the remote control, setting and executing commands.
● When a command is executed, it calls the corresponding method in the TaskManager interface (addTask, deleteTask,
etc.).
● This pattern allows you to add new actions easily by creating new command classes without changing the invoker or the
task manager. It also provides flexibility in how commands are executed, such as queuing, logging, or undoing actions.

// Command.java
public interface Command {
void execute();
}

// AddTaskCommand.java (Concrete command)


public class AddTaskCommand implements Command {
private TaskManager taskManager;
private Task task;

public AddTaskCommand(TaskManager taskManager, Task task) {


this.taskManager = taskManager;
this.task = task;
}

@Override
public void execute() {
taskManager.addTask(task);
}
}

// DeleteTaskCommand.java (Concrete command)


public class DeleteTaskCommand implements Command {
private TaskManager taskManager;
private Task task;

public DeleteTaskCommand(TaskManager taskManager, Task task) {


this.taskManager = taskManager;
this.task = task;
}

@Override
public void execute() {
taskManager.deleteTask(task);
}
}

// DisplayTaskDetailsCommand.java (Concrete command)


public class DisplayTaskDetailsCommand implements Command {
private TaskManager taskManager;
private Task task;

public DisplayTaskDetailsCommand(TaskManager taskManager, Task task) {


this.taskManager = taskManager;
this.task = task;
}

@Override
public void execute() {
taskManager.displayTaskDetails(task);
}
}

// TaskManagerInvoker.java (Invoker)
public class TaskManagerInvoker {
private Command command;

public void setCommand(Command command) {


this.command = command;
}

public void executeCommand() {


command.execute();
}
}

// Main.java (Client code)


public class Main {
public static void main(String[] args) {
TaskManager taskManager = new BaseTaskManager();
Task task1 = new Task(1, "Task 1", "Description 1");

// Create commands
Command addCommand = new AddTaskCommand(taskManager, task1);
Command deleteCommand = new DeleteTaskCommand(taskManager, task1);
Command displayCommand = new DisplayTaskDetailsCommand(taskManager, task1);

// Invoker
TaskManagerInvoker invoker = new TaskManagerInvoker();

// Set and execute commands


invoker.setCommand(addCommand);
invoker.executeCommand();

invoker.setCommand(deleteCommand);
invoker.executeCommand();

invoker.setCommand(displayCommand);
invoker.executeCommand();
}
}

Observer Design Pattern


The Observer Design Pattern is a behavioral pattern where an object, known as the subject, maintains a list of its dependents,
called observers, and notifies them of any state changes, usually by calling one of their methods. This pattern is used to
establish a one-to-many dependency between objects, ensuring that when one object changes state, all its dependents are
notified and updated automatically.

In simpler terms, the Observer pattern allows multiple objects to observe and react to changes in another object's state without
needing to be tightly coupled to it. It promotes loose coupling and flexibility in object interactions.

Let's apply the Observer Design Pattern to our Task Manager example. We'll have a TaskManager class as the subject that
maintains a list of observers (e.g., TaskObserver) and notifies them when a task is added, deleted, or modified.

import java.util.ArrayList;
import java.util.List;

// Task.java (Subject)
public class Task {
private int taskId;
private String taskName;
private String taskDescription;
private List<TaskObserver> observers = new ArrayList<>();
public Task(int taskId, String taskName, String taskDescription) {
this.taskId = taskId;
this.taskName = taskName;
this.taskDescription = taskDescription;
}

public void addObserver(TaskObserver observer) {


observers.add(observer);
}

public void removeObserver(TaskObserver observer) {


observers.remove(observer);
}

public void notifyObservers() {


for (TaskObserver observer : observers) {
observer.update(this);
}
}

// Getters and setters


}

// TaskObserver.java (Observer)
public interface TaskObserver {
void update(Task task);
}

// TaskLogger.java (Concrete Observer)


public class TaskLogger implements TaskObserver {
@Override
public void update(Task task) {
System.out.println("Logging task action: " + task.getTaskName());
}
}

// TaskManager.java (Subject)
public class TaskManager {
private List<TaskObserver> observers = new ArrayList<>();

public void addObserver(TaskObserver observer) {


observers.add(observer);
}

public void removeObserver(TaskObserver observer) {


observers.remove(observer);
}

public void notifyObservers(Task task) {


for (TaskObserver observer : observers) {
observer.update(task);
}
}
public void addTask(Task task) {
// Add task logic
notifyObservers(task);
}

public void deleteTask(Task task) {


// Delete task logic
notifyObservers(task);
}
}

// Main.java (Client code)


public class Main {
public static void main(String[] args) {
TaskManager taskManager = new TaskManager();
TaskLogger taskLogger = new TaskLogger();

// Register observer
taskManager.addObserver(taskLogger);

// Perform actions
Task task1 = new Task(1, "Task 1", "Description 1");
taskManager.addTask(task1);

Task task2 = new Task(2, "Task 2", "Description 2");


taskManager.deleteTask(task2);
}
}

Builder Design Pattern


The Builder Design Pattern is a creational pattern that separates the construction of a complex object from its representation,
allowing the same construction process to create different representations. It's useful when the construction process must
allow for different configurations of the object being built.

In simpler terms, the Builder pattern allows you to construct complex objects step by step. It's like customizing a pizza where
you can choose the crust, toppings, and sauce separately to create different combinations.

Let's apply the Builder Design Pattern to our Task Manager example. We'll create a Task class with a nested TaskBuilder
class that allows us to construct tasks with different configurations step by step.

// Task.java
public class Task {
private int taskId;
private String taskName;
private String taskDescription;

// Private constructor, only accessible through the builder


private Task(int taskId, String taskName, String taskDescription) {
this.taskId = taskId;
this.taskName = taskName;
this.taskDescription = taskDescription;
}
// Getters
public int getTaskId() {
return taskId;
}

public String getTaskName() {


return taskName;
}

public String getTaskDescription() {


return taskDescription;
}

// Nested TaskBuilder class


public static class TaskBuilder {
private int taskId;
private String taskName;
private String taskDescription;

public TaskBuilder taskId(int taskId) {


this.taskId = taskId;
return this;
}

public TaskBuilder taskName(String taskName) {


this.taskName = taskName;
return this;
}

public TaskBuilder taskDescription(String taskDescription) {


this.taskDescription = taskDescription;
return this;
}

// Build method to create Task object with configured properties


public Task build() {
return new Task(taskId, taskName, taskDescription);
}
}
}

// Main.java
public class Main {
public static void main(String[] args) {
// Using the TaskBuilder to create a Task object
Task task = new Task.TaskBuilder()
.taskId(1)
.taskName("Task 1")
.taskDescription("Description 1")
.build();

// Printing task details


System.out.println("Task ID: " + task.getTaskId());
System.out.println("Task Name: " + task.getTaskName());
System.out.println("Task Description: " + task.getTaskDescription());
}
}

MVC Design Pattern

The Model-View-Controller (MVC) pattern is a design pattern used to structure applications by separating their concerns into
three main components: Model, View, and Controller.

1. Model: Represents the application's data and business logic. It encapsulates the data and behavior of the application,
responding to requests for information and changing its state as necessary.
2. View: Represents the presentation layer of the application, responsible for displaying the data to the user. It receives
input from the user and forwards it to the controller for processing.
3. Controller: Acts as an intermediary between the model and view, handling user input and updating the model
accordingly. It receives input from the view, processes it (usually by invoking methods on the model), and updates the
view accordingly.

In simpler terms, the MVC pattern separates the concerns of an application into three distinct components: data management
(Model), user interface (View), and user interaction (Controller).

// Model: Task.java
public class Task {
private int taskId;
private String taskName;
private String taskDescription;

// Constructor, getters, setters


}

// View: TaskView.java
public class TaskView {
public void displayTaskDetails(Task task) {
System.out.println("Task ID: " + task.getTaskId());
System.out.println("Task Name: " + task.getTaskName());
System.out.println("Task Description: " + task.getTaskDescription());
}
}

// Controller: TaskController.java
public class TaskController {
private Task model;
private TaskView view;

public TaskController(Task model, TaskView view) {


this.model = model;
this.view = view;
}

public void setTaskName(String name) {


model.setTaskName(name);
}

public void setTaskDescription(String description) {


model.setTaskDescription(description);
}

public void updateView() {


view.displayTaskDetails(model);
}
}

// Main.java
public class Main {
public static void main(String[] args) {
// Create a Task object
Task task = new Task();
task.setTaskId(1);
task.setTaskName("Task 1");
task.setTaskDescription("Description 1");

// Create a TaskView object


TaskView view = new TaskView();

// Create a TaskController object


TaskController controller = new TaskController(task, view);

// Update the model


controller.setTaskName("Updated Task Name");

// Update the view


controller.updateView();
}
}

You might also like