
Play Store Application link – https://play.google.com/store/apps/details?id=com.ideepro.java25hours
Learn with youtube video-
💡Definition –
Design pattern is a general repeatable solution to a commonly occurring problem in software design.
A design pattern isn’t a finished design that can be transformed directly into code.
It is a description or template for how to solve a problem that can be used in many different situations.
IMPORTANT-
Logic type | Description | Example |
---|---|---|
Business logic | The rules and processes that govern the operation of a business or organization, such as how orders are placed, how products are manufactured or delivered, and how financial transactions are processed | A rule that defines the minimum order quantity for a particular product |
Presentation logic | The way that information is presented to users, such as the layout and formatting of a website or application, and the way that user input is validated and processed | The layout and formatting of a shopping cart page on an e-commerce site |
Data access logic | The way that a program accesses and manipulates data stored in a database or other data repository | A function that retrieves a list of customer records from a database |
Application logic | The core functionality of a program, such as the algorithms and processes that perform specific tasks or solve specific problems | An algorithm that sorts a list of numbers in ascending order |
Network logic | The way that a program communicates with other programs or devices over a network, such as through APIs or other protocols | A function that sends a request to a server to retrieve data |
💡1-Creational Patterns
These design patterns provide way to create objects while hiding the creation logic, rather than instantiating objects directly using new operator. This gives program more flexibility in deciding which objects need to be created for a given use case.
Tabular comparison of the Creational Design Patterns in Java, along with code snippets for each pattern:
Design Pattern | Description | Code Snippet |
---|---|---|
Singleton | Ensures that a class has only one instance, and provides a global access point to it. | public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } |
Factory | Creates objects without specifying the exact class to create. | public interface Animal { void speak(); } public class Dog implements Animal { @Override public void speak() { System.out.println(“Woof!”); } } public class Cat implements Animal { @Override public void speak() { System.out.println(“Meow!”); } } public class AnimalFactory { public static Animal getAnimal(String type) { if (type.equalsIgnoreCase(“DOG”)) { return new Dog(); } else if (type.equalsIgnoreCase(“CAT”)) { return new Cat(); } return null; } } |
Builder | Separates object construction from its representation, allowing the same construction process to create different representations. | public class Person { private String firstName; private String lastName; private int age; private String phone; private String address; private Person(PersonBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; } public static class PersonBuilder { private String firstName; private String lastName; private int age; private String phone; private String address; public PersonBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public PersonBuilder age(int age) { this.age = age; return this; } public PersonBuilder phone(String phone) { this.phone = phone; return this; } public PersonBuilder address(String address) { this.address = address; return this; } public Person build() { return new Person(this); } } } |
Prototype | Creates new objects by copying existing objects. | public abstract class Prototype implements Cloneable { @Override public Prototype clone() throws CloneNotSupportedException { return (Prototype) super.clone(); } } public class ConcretePrototype extends Prototype { private String field; public ConcretePrototype(String field) { this.field = field; } public String getField() { return field; } public void setField(String field) { this.field = field; } } public class Client { public static void main(String[] args) throws CloneNotSupportedException { ConcretePrototype prototype = new ConcretePrototype(“prototype”); ConcretePrototype copy = prototype.clone(); } } |
💡2-Structural Patterns
These design patterns concern class and object composition. Concept of inheritance is used to compose interfaces and define ways to compose objects to obtain new functionalities.
Tabular comparison of some of the most common structural design patterns in Java, along with code snippets for each:
Design Pattern | Description | Code Snippet |
---|---|---|
Adapter | Converts the interface of a class into another interface that clients expect. Allows classes to work together that couldn’t otherwise because of incompatible interfaces. | // The target interface that the client expects public interface Target { void request(); } // The adaptee class that needs to be adapted public class Adaptee { public void specificRequest() { // implementation of the specific request } } // The Adapter class that adapts the Adaptee to the Target interface public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void request() { // Call the specific request method on the adaptee adaptee.specificRequest(); } } // Client code that uses the Target interface public class Client { public static void main(String[] args) { Adaptee adaptee = new Adaptee(); Target target = new Adapter(adaptee); target.request(); } } |
Bridge | Decouples an abstraction from its implementation so that the two can vary independently. | public abstract class Shape { protected Color color; public Shape(Color color) { this.color = color; } abstract public void applyColor(); } public class Circle extends Shape { public Circle(Color color) { super(color); } @Override public void applyColor() { System.out.println(“Applying color to circle”); color.applyColor(); } } public class Triangle extends Shape { public Triangle(Color color) { super(color); } @Override public void applyColor() { System.out.println(“Applying color to triangle”); color.applyColor(); } } public interface Color { void applyColor(); } public class Red implements Color { @Override public void applyColor() { System.out.println(“Applying red color”); } } public class Green implements Color { @Override public void applyColor() { System.out.println(“Applying green color”); } } |
Composite | Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. | public interface Component { void operation(); } public class Leaf implements Component { public void operation() { // operation on leaf } } public class Composite implements Component { private List children = new ArrayList<>(); public void operation() { for (Component child : children) { child.operation(); } } public void add(Component component) { children.add(component); } public void remove(Component component) { children.remove(component); } public Component getChild(int index) { return children.get(index); } } |
Decorator | Dynamically adds new behavior to an existing object without changing its interface. | public interface Component { void operation(); } public class ConcreteComponent implements Component { public void operation() { // original operation } } public abstract class Decorator implements Component { protected Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } } public class ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component component) { super(component); } @Override public void operation() { super.operation(); // additional behavior } } public class ConcreteDecoratorB extends Decorator { public ConcreteDecoratorB(Component component) { super(component); } @Override public void operation() { super.operation(); // additional behavior } } |
Facade | Provides a simplified interface to a complex system of classes, hiding the implementation details. | public class Facade { private SubsystemA subsystemA; private SubsystemB subsystemB; private SubsystemC subsystemC; public Facade(SubsystemA subsystemA, SubsystemB subsystemB, SubsystemC subsystemC) { this.subsystemA = subsystemA; this.subsystemB = subsystemB; this.subsystemC = subsystemC; } public void operation() { subsystemA.operation(); subsystemB.operation(); subsystemC.operation(); } } |
Flyweight | Conserves memory by sharing large numbers of fine-grained objects efficiently. | public interface Flyweight { void operation(); } public class ConcreteFlyweight implements Flyweight { private int state; public ConcreteFlyweight(int state) { this.state = state; } public void operation() { // operation using state } } public class FlyweightFactory { private Map flyweights = new HashMap<>(); public Flyweight getFlyweight(int state) { Flyweight flyweight = flyweights.get(state); if (flyweight == null) { flyweight = new ConcreteFlyweight(state); flyweights.put(state, flyweight); } return flyweight; } } |
Proxy | Provides a surrogate or placeholder for another object to control access to it. | public interface Subject { void operation(); } public class RealSubject implements Subject { public void operation() { // real subject operation } } public class Proxy implements Subject { private Subject subject; public Proxy(Subject subject) { this.subject = subject; } public void operation() { subject.operation(); } } |
💡3-Behavioral Patterns
These design patterns are specifically concerned with communication between objects.
Behavioral Design Pattern | Description | Code Snippet |
---|---|---|
Strategy | Allows for interchangeable behavior in a class by using different algorithms or strategies | public interface PaymentStrategy { void pay(int amount); }public class CreditCardPayment implements PaymentStrategy { public void pay(int amount) { // code to process credit card payment } }public class CheckPayment implements PaymentStrategy { public void pay(int amount) { // code to process check payment } } |
Observer | Allows for one object to notify other objects of changes in state | public interface Observer { void update(int value); }public class ConcreteObserver implements Observer { public void update(int value) { // code to update state based on value } }public class Subject { private List<Observer> observers; public void attach(Observer observer) { observers.add(observer); } public void notifyObservers(int value) { for (Observer observer : observers) { observer.update(value); } } } |
Command | Encapsulates a request as an object, allowing for the request to be passed around and executed at a later time | public interface Command { void execute(); }public class ConcreteCommand implements Command { private Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } public void execute() { receiver.action(); } }public class Receiver { public void action() { // code to perform desired action } } |
State | Allows an object to alter its behavior when its internal state changes | public interface State { void handle(); }public class ConcreteStateA implements State { public void handle() { // code to handle state A } }public class ConcreteStateB implements State { public void handle() { // code to handle state B } }public class Context { private State state; public void setState(State state) { this.state = state; } public void request() { state.handle(); } } |
Iterator | Allows for the traversal of a collection without exposing its internal structure | import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class IteratorExample { public static void main(String[] args) { List names = new ArrayList<>(); names.add(“Alice”); names.add(“Bob”); names.add(“Charlie”); names.add(“Dave”); // Create an iterator to traverse the list of names Iterator<String> iterator = names.iterator(); // Use the iterator to traverse the list while (iterator.hasNext()) { String name = iterator.next(); System.out.println(name); } } } |
Mediator | Allows for the communication between objects without them being aware of each other’s existence | public interface Mediator { void send(String message, Colleague colleague); }public class ConcreteMediator implements Mediator { private Colleague colleagueA; private Colleague colleagueB; public void setColleagueA(Colleague colleagueA) { this.colleagueA = colleagueA; } public void setColleagueB(Colleague colleagueB) { this.colleagueB = colleagueB; } public void send(String message, Colleague colleague) { if (colleague == colleagueA) { colleagueB.receive(message); } else { colleagueA.receive(message); } } }<br |
💡4-J2EE Patterns
These design patterns are specifically concerned with the presentation tier. These patterns are identified by Sun Java Center.
Design Pattern | Description | Code Snippet |
---|---|---|
Model-View-Controller (MVC) | Model: The model represents the data and the business logic of the application. It is responsible for storing and manipulating the data, and for performing any calculations or processing required by the application. View: The view is responsible for presenting the data to the user. It is typically implemented as a GUI, and it displays the data to the user and handles user input. Controller: The controller acts as the intermediary between the model and the view. It receives user input, updates the model as needed, and then updates the view to reflect the changes in the model. | public class MVCExample { public static void main(String[] args) { // Create the model, view, and controller Model model = new Model(); View view = new View(model ); Controller controller = new Controller(model, view); // Set the initial data in the model model.setData(“Hello, World!”); // Update the view to display the initial data view.update(); // Handle user input to update the model and view controller.handleInput(“Goodbye, World!”); } } class Model { private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } } class View { private Model model; public View(Model model) { this.model = model; } public void update() { System.out.println(model.getData()); } } class Controller { private Model model; private View view; public Controller(Model model, View view) { this.model = model; this.view = view; } public void handleInput(String input) { model.setData(input); view.update(); } } |
Business Delegate | The business delegate separates the presentation layer (view) from the business logic (model). It provides a separation between the presentation-tier client and the business services tier. This separation enables the development of presentation-tier components that are decoupled from the underlying business logic. | public class BusinessDelegate { private BusinessLookUp lookupService = new BusinessLookUp(); private BusinessService businessService; private String serviceType; public void setServiceType(String serviceType){ this.serviceType = serviceType; } public void doTask(){ businessService = lookupService.getBusinessService(serviceType); businessService.doProcessing(); } } |
Front Controller | The front controller is a design pattern that provides a centralized request handling mechanism so that all requests for a Web application go through a single handler. This handler can do the authentication/ authorization/ logging or tracking of request and then pass the requests to corresponding handlers. | public class FrontController { private Dispatcher dispatcher; public FrontController(){ dispatcher = new Dispatcher(); } private boolean isAuthenticUser(){ System.out.println(“User is authenticated successfully.”); return true; } private void trackRequest(String request){ System.out.println(“Page requested: ” + request); } public void dispatchRequest(String request){ //log each request trackRequest(request); //authenticate the user if(isAuthenticUser()){ dispatcher.dispatch(request); } } } |
Data Access Object (DAO) | The DAO pattern is used to separate the high-level business logic from the low-level data access logic. It provides a separation of concerns and can be used to reduce the duplication of data access code. | public interface StudentDao { public List getAllStudents(); public Student getStudent(int rollNo); public void updateStudent(Student student); public void deleteStudent(Student student); } public class StudentDaoImpl implements StudentDao { //list is working as a database List students; public StudentDaoImpl(){ students = new ArrayList(); Student student1 = new Student(“Robert”,0); Student student2 = new Student(“John”,1); students.add(student1); students.add(student2); } public void deleteStudent(Student student) { students.remove(student.getRollNo()); System.out.println(“Student: Roll No ” + student.getRollNo() + “, deleted from database”); } //retrive list of students from the database public List getAllStudents() { return students; } public Student getStudent(int rollNo) { return students.get(rollNo); } public void updateStudent(Student student) { students.get(student.getRollNo()).setName(student.getName()); System.out.println(“Student: Roll No ” + student.getRollNo() + “, updated in the database”); } } |
Composite Entity | The composite entity pattern is used to represent a graph of objects that can be treated in the same way as a single entity. It is used to represent a complex entity that is composed of multiple simple entities. | public class CompositeEntity { private CoarseGrainedObject cgo = new CoarseGrainedObject(); public void setData(String data1, String data2){ cgo.setData(data1, data2); } public String[] getData(){ return cgo.getData(); } } |
Intercepting Filter | The intercepting filter pattern is used to intercept requests and responses of a Web application. It can be used to perform tasks such as authentication, logging, or to add additional functionality to a Web application. | public class AuthenticationFilter implements Filter { public void execute(String request){ System.out.println(“Authenticating request: ” + request); } } |
Service Locator | The service locator pattern is used to locate and cache the objects that make up the services of a Web application. It is used to decouple the presentation layer from the business logic. | public class ServiceLocator { private static Cache cache; static { cache = new Cache(); } public static Service getService(String jndiName){ Service service = cache.getService(jndiName); if(service != null){ return service; } InitialContext context = new InitialContext(); Service service1 = (Service)context.lookup(jndiName); cache.addService(service1); return service1; } } |
Transfer Object | The transfer object pattern is used to transfer data between layers of a Web application. It is used to reduce the number of method calls between layers and to reduce the complexity of the business logic. | public class StudentBO { //list is working as a database List students; public StudentBO(){ students = new ArrayList(); Student student1 = new Student(“Robert”,0); Student student2 = new Student(“John”,1); students.add(student1); students.add(student2); } public void deleteStudent(Student student){ students.remove(student.getRollNo()); System.out.println(“Student: Roll No ” + student.getRollNo() + “, deleted from database”); } //retrive list of students from the database public List getAllStudents(){ return students; } public Student getStudent(int rollNo){ return students.get(rollNo); } public void updateStudent(Student student){ students.get(student.getRollNo()).setName(student.getName()); System.out.println(“Student: Roll No ” + student.getRollNo() + “, updated in the database”); } } |
Interview Questions —
- What is advantage of design pattern in programming?
- What is factory pattern?
- What is singleton pattern?