Java Design Pattern Interview Questions and Answers

Java is among the most widely used programming languages. Java design pattern corresponds to quick fixes for commonly occurring problems in Java programming. Java developers are high in demand all over the world. Hence, it is essential for any Java developer to have a robust understanding of Java design patterns. Whether you are a beginner, intermediate or advanced level, these Java design pattern interview questions are designed to help you better your understanding of the popular object-oriented programming language. These interview questions go in-depth into Java design patterns, including topics varying from types of design patterns and explanations with code to real-world examples and related topics. Additionally, we will also cover topics such as deadlock, memory management, and concurrency. Whether you’re looking forward to crack your next interview or land a job in Java development, these Java interview questions will prove to be an invaluable resource for you.

  • 4.7 Rating
  • 65 Question(s)
  • 35 Mins of Read
  • 6674 Reader(s)

Beginner

Java design patterns save developers from tackling the same problems over and over by providing them with a specific set of readily available solutions. This allows Java developers to focus more on logic development and less on writing the same code all over again.

Interestingly, design patterns are repeatable solutions to commonly occurring problems. They are almost similar for different programming languages. Java design patterns are important as they help to define the architecture of a software. Also, Java design patterns enhance reusability in Java by providing solutions that can be easily replicated across programs.

This is one of the most frequently asked Java Design Pattern Interview questions for experienced professionals.

Command, Factory Design, Observer, Singleton, and Structural design patterns are 5 of the most used design patterns in Java: 

  1. Command Design Pattern - This Java design pattern helps to identify issues due to loss of coupling between classes and objects. 
  2. Factory Design Pattern - It is a creational pattern that helps to create an object while hiding its creation logic from the user. 
  3. Observer Design Pattern - This design pattern is used to create multiple dependencies. Deciding the chain of dependency is important while implementing the observer design pattern. 
  4. Singleton Design Pattern - Excellent for creating a single-purpose instance. 
  5. Structural Design Pattern – This design pattern is ideal when an add-on class is required. It induces a private constructor. 

Expect to come across this important design patterns question in Java Design Pattern Interviews.

All Java design patterns can be classified into four types, namely behavioral, creational, structural, and miscellaneous. 

  1. Behavioral Java Design Patterns - These design patterns in Java provide solutions for better interaction between objects. Chain Of Responsibility, Command, Mediator, Memento, Observer, Strategy, and Template are some notable examples. 
  2. Creational Java Design Patterns - We use creational design patterns to instantiate an object in the most suitable way depending on the situation. Abstract Factory, Builder, Factory, Prototype, and Singleton fall under this category of Java design patterns. 
  3. Structural Java Design Patterns - These provide various ways to create a class structure. Adapter, Composite, Decorator, Facade, Flyweight, and Proxy are structural design patterns in Java. 
  4. Miscellaneous Java Design Patterns - Java design patterns that don’t fit in the above 3 categories come under this classification. Examples include DAO, DI, and MVC. 

Leave for the miscellaneous design patterns, the trio is collectively known as Gang of Four (GoF) design patterns. 

The factory design pattern is one of the most popular Java design patterns that happens to be a creational design pattern. A creational Java design pattern offers the best way to instantiate an object in a particular scenario. Abstract Factory, Builder, Prototype, and Singleton are also creational design patterns in Java. 

While working with the Java programming language, we usually need to develop code that doesn’t give away the logic for creating objects to the client. Among all the creational design patterns, we use the factory design pattern frequently for hiding the object creation logic from the client.

Design patterns can be simply understood as template solutions for recurring problems in software development. While different programming languages have different sets of design patterns, the end goal is the same; to facilitate writing code and developing programs. While certain design patterns are built into the programming language, others are universal.

Design patterns is a wide-ranging term that isn’t just limited to the Java programming language. In general, design patterns correspond to a particular set of techniques that are reusable and efficient. We use them to solve common issues experienced in software development. 

In the context of Java, Java design patterns are methodologies and rules to help developers save a sizable amount of time and effort in developing code for a particular application or website. These also help to develop software that has robust code and is easy to modify as per the evolving requirements.

Java is one of the most popular programming languages. As such, it enjoys a wide community that is continually busy in developing software with Java. Consequently, there are a slew of design patterns available for Java developers to build software based on different requirements. Some of the most popular Java design patterns are: 

  1. Factory Design Pattern - It is a creation design pattern where objects are created without expressing logic to the client. 
  2. Chain Responsibility Pattern - A behavioral design pattern where requests are passed via a chain of handlers. 
  3. Decorator Design Pattern - It is a structural design pattern. It allows developers to add new features to an existing object without modifying the structure. 
  4. MVC Design Pattern - This Java design pattern splits the software into three parts, namely Model, View, and Controller. 
  5. Prototype Pattern - It is a creative design pattern. 

There are several advantages of leveraging java design patterns. Some of the most important ones are: 

  • Java design patterns make an application's design transparent. 
  • The design patterns in Java help to document experiences in software engineering. 
  • Multiple projects can use the Java design patterns. 
  • The system architecture can be defined with the help of design patterns. 

Simply put, Java design patterns are readily available solutions to frequently occurring issues. 

A must-know for anyone heading into a Java Design Pattern interview, this question is frequently asked in Java Design Pattern Interviews.

The concept of design patterns was created by the four superheroes (developers) known as the Gang of Four (GOF), namely Erich Gamma, Ralph Johnson, Richard Hel, and John Vlissides. In 1994, these authors published a book titled "Design Patterns: Elements of Reusable Object-Oriented Software" which contained documentation of Java design patterns. 

The book mentioned a total of 23 design patterns that were further classified into behavioral, creational, and structural design patterns. 

When it comes to class compositions and object structures, structural patterns are employed to offer answers and practical standards. To enable various objects or classes to cooperate and form a single functional whole, structural patterns in Java utilize the concepts of inheritance and interfaces. 

Adapter, Bridge, Decorator, Facade, and Proxy are some of the most popular structural patterns in Java. 

Design patterns for creating things have to do with how things are made. When a choice is made and when a class is created, creational design patterns are used. 

Employee emp=new Employee(); 

In this case, we are generating the instance using the new keyword because it is used in Java to construct an object. Sometimes, it's necessary to modify an object's nature to fit the program's needs. We should apply creational design patterns in these situations to offer a more all-encompassing and adaptable solution. 

To gain sequential access to the elements of a collection object, you can leverage the iterator pattern. Other than the Java programming language, the iterator pattern is also widely used in .NET. It is a behavioral design pattern. 

In addition to facilitating the access to the elements of a collection object in a sequential manner, the design pattern doesn’t require the knowledge of underlying representation of the collection object. 

We use the service locator pattern while utilizing JNDI (Java Naming and Directory Interface) to find different services. JNDI is an API that enables directory and naming functionality in Java applications. 

The service locator pattern is anti-pattern and should be avoided. An anti-pattern in Java is a solution to a frequently occurring problem that must not be used. This is because using Java anti-patterns leads to bad software design and technical debt. 

It's no surprise that this one pops up often in Java Design Pattern questions in Java.

The bridge pattern is used when we want to separate abstraction from its implementation so that they can change independently. It is a structural design pattern that leverages aggregation and encapsulation - and inheritance in certain cases - to distribute responsibilities into classes. 

It was introduced by the Gang of Four and is often confused with the adapter pattern, which is also a structural pattern that helps existing classes to work with other classes without the need to alter their source code. 

This pattern limits the number of times a class can be instantiated and guarantees that there is only one instance of the class in the Java Virtual Machine among many. The implementation procedure is complicated even though it is a one-time fix.

There are two steps that need to be followed to create a singleton class in Java and those are: 

  1. To prevent the class from being instantiated using the new operator, make the constructor private. 
  2. If the object is not null, return an object of it; if not, create the object and return it via a method. 

The singleton pattern is one of the most used design patterns in Java. It helps to ensure that a class has only one instance that has global access. However, to prevent the Java design pattern from breaking you need to prevent cloning (reflection.clone) and serialization.

There are several approaches to constructing a thread-safe singleton in Java, such as utilizing a static singleton instance that is initialized during class loading or employing double-checked locking. The simplest approach to generate a thread-safe singleton is with a Java enum.

The following are some of the DAO entities: 

  • Concrete class for data access object 
  • Object interface for data access 
  • Value object or model object
Static Class
Singleton Class

Any time a member of the class is accessed, memory is immediately allocated. 

As soon as the object creation is done, memory allocation happens. 

Only static members can be found in static classes. 

It can have both static and instance members. 

Cannot be used as a method parameter. 

Can be used as a method parameter. 

It uses stack memory. 

It uses heap memory. 

The Factory Pattern is used in the following conditions: 

  • When you want a sub-class to choose the type of objects to create. 
  • When a class is unsure of the class of objects it should create. 
  • If you want to construct an object of any subclass based on the provided data, you can use the factory pattern. 

Proxy design patterns belong to the structural design subcategory that reflects the functionality of other classes. By using this pattern, programmers can create a replacement for another object. A proxy object makes it easier to restrict access to the original object and gives us the ability to handle many tasks either before or after the request is sent to the original object.

Different types of proxies are: 

  • Virtual Proxy - Used to prevent memory from being assigned to an object that might not be needed again in the future. A lite copy of the object is made and displayed to the user as long as it is not in use; this copy contains all necessary information. Virtual proxy prevent memory from being assigned to an object that might not be needed again in the future. An image of the object is produced and displayed to the user until it is not used. 
  • Protection Proxy - Control access to the real subject. 
  • Smart Proxy - Used to track calls to the members of the underlying object. 
  • Caching Proxy - Used to save costly calls to the actual subject. 
  • Remote Proxy - Used in distributed object communication.

The Singleton Pattern's implementation procedure is referred to as eager initialization. At this point, the Singleton Class instance is curated when the class is loaded. The disadvantage of this approach is that a singleton class is generated even if the client's application might not be using it. Nonetheless, it is the simplest way to curate a singleton class.

It is categorized as a structural design pattern. The Bridge Design Pattern is used to separate the implementation from the interfaces. The client programs are shielded from the implementation specifics by doing this. When interface hierarchies exist in both interfaces and implementations, the Bridge Design Pattern is mostly necessary.

The Bridge Pattern is seen in the aforementioned UML diagram. The bridge Pattern is made up of 4 primary components, namely Abstraction, Refined Abstraction, Implementor, Concrete Implementor.

Decorator design patterns fall under the topic of structural patterns, which enable users to add new functionality to an item without changing its structure. By maintaining the method signatures of the existing class, this technique generates a class called decorator class that serves as a wrapper to the original class.

To implement the wrapper, this approach uses composition-based interfaces and abstract classes. Considering that we categorize functionalities into different classes, they are mostly employed to implement the SRP (Single Responsibility Principle). This pattern is structurally comparable to the chain of responsibility pattern.

Intermediate

A common and most important design patterns in Java for interview, don't miss this one.

Inversion of Control (IoC) is a design principle (some label it a pattern as well) that helps to decouple the dependencies among components and layers in a system. In other words, it helps to remove dependencies in the code. Dependency Injection (DI) is a typical example of IoC. 

Let's understand it with a quick example. Suppose we have two classes X and Y that are bound by a dependency such that class B uses class A. We have the code: 

public class Y{private X x; 
public Y() {this.x = new X(); 
} 
} 

As you can see above, there is a dependency between X and Y. Had we followed the Inversion of Control principle, we would have avoided the use of new for assigning value to the dependent variable, i.e. x. Instead, we have written something like this if were to follow the IoC design principle: 

public class Y{private IoCA x; 
public Y(IoCA x){this.x = x; 
} 
} 

While design patterns are templates for developing solutions to commonly encountered problems in software development, design principles are rules that are followed when developing software.

Design Patterns vs Design Principles

Parameter 

Design Patterns 

Design Principles 

Definition 

Design patterns are templates that serve as quick fixes for commonly occurring issues in software development. 

These are guidelines followed when developing software. 

Intended to 

Minimize problems occurring while developing software. 

Ensure developing robust, extensible, reliable, and efficient software. 

Type 

Tested-and-trusted solutions 

General guidelines 

Examples 

  • Factory design pattern 
  • Singleton pattern 
  • MVC 
  • Prototype design pattern 
  • SOLID (Single-responsibility, Open-closed, Liskov substitution, Interface segregation, Dependency inversion) 
  • DRY (Don’t Repeat Yourself) 

A complicated item is created utilizing small objects and a step-by-step process using a builder pattern. Other items are not dependent on this builder. 

The Director class, which is optional, is used to ensure that the building steps are carried out with the appropriate data and by the appropriate builder. It has to do with delegation and validation.

Method chaining, also known as "Fluent Interface syntax," can be used to present the invocations of the steps of the Builder/Director pattern semantically.

Employee emp = new emp.Builder() 
                       .name(true) 
                       .rollno(true) 
                       .age(true) 
                       .build();

One of the most frequently asked Design Patterns in Java interview questions and answers, be ready for it.

The dependency injection (DI) design pattern facilitates loose coupling when dependencies are involved; note that it doesn’t eliminate program dependencies. 

In the following scenario, we offer information sourced from an external file, such as an XML one. Our code becomes more decoupled as a result, making testing simpler. Here, we write the code as: 

class Student{   
Sname sname;   
Student(Sname sname){   
this.sname=sname;   
}   
public void setSname(Sname sname){   
this.sname=sname;   
} 
} 

In the above code, either the constructor or the setter method uses an external source, such as an XML file, to supply an instance of the Student class. 

The adapter design pattern is an example of a structural design pattern that enables cooperation between different items. It serves as a barrier between two distinct objects. The adapter responds to a request from one object and alters it so that it may be recognized by another object.

Imagine you have an Animal class with the methods fly() and makeSound(). The Duck class also has a squeak() method. Let's say you don't have enough Duck items and want to substitute Animal objects in their place. We cannot directly use animals because they implement a distinct interface despite having some functionality that is similar. Thus, we shall employ the adapter pattern. 

In the following case, Duck would be our client and Animal would be the adaptee. 

// Java implementation of the Adapter pattern
interface Animal 
{ 
// birds implement Bird interface that allows 
// them to fly and make sounds adaptee interface 
public void fly(); 
public void makeSound(); 
} 
class Sparrow implements Animal 
{ 
// a concrete implementation of animal 
public void fly() 
{ 
System.out.println("Flying"); 
} 
public void makeSound() 
{ 
System.out.println("Chirp Chirp"); 
} 
} 
interface Duck 
{ 
// target interface 
// ducks dont fly they just make 
// squeaking sound 
public void squeak(); 
} 
class PlasticToyDuck implements Duck 
{ 
public void squeak() 
{ 
System.out.println("Squeak"); 
} 
}
class AnimalAdapter implements Duck 
{ 
// You need to implement the interface your 
// client expects to use. 
Animal animal; 
public AnimalAdapter(Animal animal) 
{ 
// we need reference to the object we 
// are adapting 
this.animal = animal; 
} 
public void squeak() 
{ 
// translate the methods appropriately 
animal.makeSound(); 
} 
} 
class Main 
{ 
public static void main(String args[]) 
{ 
Sparrow sparrow = new Sparrow(); 
Duck duck = new PlasticToyDuck(); 
// Wrap a bird in a birdAdapter so that it 
// behaves like toy duck 
Duck aniAdapter = new AnimalAdapter(sparrow); 
System.out.println("Sparrow..."); 
sparrow.fly(); 
sparrow.makeSound(); 
System.out.println("Duck..."); 
duck.squeak(); 
// toy duck behaving like a bird 
System.out.println("AnimalAdapterAdapter..."); 
aniAdapter.squeak(); 
} 
} 

Output: 

Factors that one should consider before using the flyweight pattern are: 

  • The curation of objects might take a lot of time and memory. 
  • Both intrinsic and extrinsic features can be categorized as attributes. 
  • The extrinsic characteristics of the Object should be made clear by the client software. 
  • The application should create a large number of objects. 

A staple in Java Design Pattern Interview Questions for experienced, be prepared to answer this one.

When there is a one-to-many relationship between items, such as when a modified object needs to automatically notify dependent objects, the observer pattern is employed. The behavioral pattern category includes observer patterns. 

The implementations of the Observer Design Pattern are as follows: 

  • javax.servlet.http.HttpSessionAttributeListener 
  • java.util.EventListener in Swing 
  • javax.servlet.http.HttpSessionBindingListener 

When an object alters its behavior based on its internal state, the state design pattern is applied. If we need to alter an object's behavior based on its state, we may save the state as a variable in the object and use an if-else condition block to take various actions according to the state. 

Through the implementation of Context and State, the State pattern offers a methodical and decoupled way to accomplish this. 

Example:

class AlertStateContext{ 
private MobileAlertState currentState; 
public AlertStateContext() 
{ 
CurrentState = newVibration(); 
} 
public void setState(MobileAlertState state) 
{ 
 currentState = state; 
} 
public void alert() 
{ 
currentState.alert(this); 
  }} 
class Vibration implements MobileAlertState 
{ 
public void alert(AlertStateContext ct) 
{ 
System.out_printin(vibration state."); 
} 
 } 
class Silent implements MobileAlertState  
{ 
public void alert(AlertStateContext ct) 
{ 
System.out.printin(silent state."); 
} 
class StatePattern{ 
public static void main(String{args){ 
AlertStateContext stateContext = new AlertStateContext(); 
stateContext.alert(); 
stateContext.setState(new Silent()); 
StateContext.alert()} 

Output:

Behavioral Design Patterns include the Command Pattern. Under the request-response model, it is utilized to implement loose coupling. The request is delivered to the invoker in this process, who then passes it on to the command Object. The command object then sends the request to the receiver's appropriate method. Additionally, the receiver carries out the designated action.

The Base Component, Leaf, and Composite are the various Objects of the Composite Design Pattern. 

  1. The interface that all Objects in the composition used is called Base Composite. This component is preferred by the client software for use with the composition's objects. 
  2. Leaf contributes to the composition's behavior definition. There is no reference to any other components included with this object. It implements fundamental elements and serves as a foundational element for the composition. 
  3. The process is carried out in the base component by the composite, which also carries leaf elements. 

Algorithms and design patterns both outline typical solutions to a variety of issues. The major distinction, though, is that while a design pattern offers a high-level description of any solution, an algorithm specifies a precise set of steps for achieving a goal.

Even though two separate problems may use the same design pattern, the implementation logic will vary depending on the needs.

A builder pattern is a type of creational design pattern that enables you to build complex objects piece by piece. Through the same logic of construction, the pattern enables you to create many representations of an item. 

It facilitates the development of immutable classes with several characteristics. If the object has multiple properties, you run into these issues in both the Factory and Abstract Factory Design Patterns: 

  1. When the client passes too many arguments to the Factory Class in a specific order, the application becomes more prone to errors. When the types are the same, it becomes challenging to maintain the order of these arguments. 
  2. The intricacy of this class will become confusing when an object's creation becomes complicated due to numerous characteristics. 
  3. The object may have optional attributes. And yet, you can be forced to send Null values for all of the optional properties and parameters. 

This pattern provides a technique to construct an object in a step-by-step approach and return the finished object through another method, helping to tackle the problem of a large number of optional characteristics and the inconsistent condition. 

Implementation of builder pattern is shown below: 

  • Copy all of the arguments from the outer class into a static nested class: the builder class will be this nested class. The builder class's name must adhere to a proper naming convention. For instance, the builder will be called SampleBuilder if the class is called Sample. 
  • The public constructor for the builder class must be public and accept all of the characteristics as input. 
  • Additionally, the builder class ought to provide methods for setting optional arguments and returning the builder object after doing so. 
  • To return the object needed by the client, the construct() method must be present inside the builder class. 

The distinction between JDO and VO is that the former is a persistent technology that challenges entity beans in the creation of corporate applications. You can produce POJOs (plain old Java objects) and persist them to the database using this tool.

Value objects, or VOs, are an abstract design pattern that may be utilized with entity beans, jdbc, and possibly even JDO to solve typical isolation and transactional issues in corporate apps.

Use Setter injection to supply an object's optional dependencies, and Constructor injection to offer an object's mandatory dependence, without which it will not function.

This inquiry also relates to the Dependency Injection design pattern and is frequently posed in relation to the Spring framework, which has now established itself as the de facto tool of choice for creating Java applications.

Since Spring offers an IOC container, you have the option to declare dependencies using constructors or setter methods.

The Java concurrency design pattern known as Producer-Consumer can be implemented in a variety of ways. If you're using Java 5, it's preferable to implement the producer-consumer pattern using concurrency rather than Java's default wait and notify method. 

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
public class ProducerConsumerPattern {
public static void main(String args[]){ 
     //Creating shared object 
 BlockingQueue sharedQueue = new LinkedBlockingQueue(); 
 //Creating Producer and Consumer Thread 
 Thread prodThread = new Thread(new Producer(sharedQueue)); 
 Thread consThread = new Thread(new Consumer(sharedQueue));   
     //Starting producer and Consumer thread 
 prodThread.start(); 
 consThread.start(); 
}   
}  
//Producer Class in java 
class Producer implements Runnable { 
private final BlockingQueue sharedQueue;  
public Producer(BlockingQueue sharedQueue) { 
    this.sharedQueue = sharedQueue; 
}  
@Override 
public void run() { 
    for(int i=0; i<10; i++){ 
        try { 
            System.out.println("Produced: " + i); 
            sharedQueue.put(i); 
        } catch (InterruptedException ex) { 
            Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex); 
        } 
    } 
}  
} 
//Consumer Class in Java 
class Consumer implements Runnable{ 
private final BlockingQueue sharedQueue; 
public Consumer (BlockingQueue sharedQueue) { 
    this.sharedQueue = sharedQueue; 
} 
@Override 
public void run() { 
    while(true){ 
        try { 
            System.out.println("Consumed: "+ sharedQueue.take()); 
        } catch (InterruptedException ex) { 
            Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex); 
        } 
    } 
}  
} 

Another common core Java design pattern interview question is about the Template pattern. It has frequently appeared in actual projects, in my experience. The template pattern allows the subclass to implement specific steps while outlining an algorithm in the form of a template method.

When addressing this query, it is crucial to emphasize that the template method should be final in order to prevent subclasses from overriding and altering the algorithm's phases. Individual steps should be abstract, nonetheless, so that child classes can carry them out.

In such a scenario, we can leverage the object-oriented design pattern in Java. While developing code for the Smartphone class we need to ensure that it is both flexible and stable. 

The object-oriented design pattern features a pattern of fixed class structure and messaging that can be readily used multiple times. It appears as a useful and elegant programming idiom. 

It must be flexible to facilitate the creation of derived classes in the future while the stability will ensure that any required changes to the existing classes can be made without any issues. 

If you’re involved in financial services development, then you should know how to add market data to your Java program effortlessly and efficiently. 

One way to implement the aforementioned scenario is to develop an interface that can be called MarketAnalysis, MarketData, or something like that. It will have methods like getBid() and getPrice(). 

Moreover, the interface must be able to add market data provided by different vendors and thus have a MarketDataProvider method implemented using DI. Doing so will allow the client to change market data sources - Reuters, Bloomberg, or S&P Global Market Intelligence - without any hassle. 

Java is immensely popular for its platform-agnostic operation. Java Memory Model is the collection of certain guidelines and rules that facilitate the creation of Java programs that perform reliably and as intended across different operating systems, CPUs, hardware configurations, and memory architecture. It is the most useful when aiming for multi-threading. 

Java Memory Model allows setting the changes made by a thread that must be visible for others. Let’s take the example of the happens-before relationship. 

It ensures that if X happens before Y, and Y happens before Z, then X happens before Z. This guarantees transitivity. Other things ensured by a happens-before relationship are volatile variable rule, program order rule, and monitor lock rule. 

When two or more threads (or processes) in Java wait for each other’s resources then we can say that a deadlock has occurred. Usually, it happens when different threads need the same locks but get them in different orders. 

Deadlock is a major issue when achieving multithreading in Java. Livelock is a special case of resource starvation. The state of a thread doesn’t change in a deadlock. Compared to a deadlock, the states of the threads or processes involved change continuously with respect to one another in a livelock. 

Advanced

Factory design pattern is a creational design pattern. This is followed to shield the logic of object creation from the client. It is done by making use of factory classes and interfaces available in Java. Two important benefits of implementing the Factory Design Pattern are: 

  1. It introduces flexibility to implement methods while new classes are introduced. This introduces loose coupling in the software. 
  2. It allows developers to test the seamlessness of the software with mock or stubs. 

Let’s understand the Factory Design Pattern using the ShapeFactory class. We’ll use it to create three concrete classes, namely Rectangle, Square and Triangle. The Driver class would be passing the information to get the required object, i.e., rectangle, square, or triangle. 

We’ll start with creating a Shape interface: 

public interface Shape {void draw(); 
} 

The next step is to create 3 concrete classes, which are Rectangle, Square, and Triangle. Each one of them will implement the Shape interface: 

//Rectangle 
public class Rectangle implements Shape { 
@Override 
public void draw() {System.out.println("This is a Rectangle!"); 
} 
} 
//Square 
public class Square implements Shape { 
@Override 
public void draw() {System.out.println("This is a Square!"); 
} 
} 
//Triangle 
public class Triangle implements Shape { 
@Override 
public void draw() {System.out.println("This is a Triangle!"); 
} 
} 

The next step is to create a class and a method for generating objects of the concrete classes. We can label the class as FactoryShape class and the method as getShapeDesign(): 

public class FactoryShape { 
public Shape getShapeDesign (String type) { 
if (type == null) {return null; 
} 
if (type.equalsIgnoreCase("TRIANGLE")) {return new Triangle(); 
} else if (type.equalsIgnoreCase("SQUARE")) {return new Square(); 
} else if (type.equalsIgnoreCase("RECTANGLE")) {returns new Rectangle(); 
} 
return null; 
} 
} 

Now, we implement the Driver class and use the factory class to get the object of a specific shape: 

public class Driver{ public static void main(String[] args) { 
FactoryShape factoryShape = new FactoryShape(); 
Shape triangle = factoryShape.getShape("TRIANGLE"); 
triangle.draw(); 
Shape rectangle = factoryShape.getShape("RECTANGLE"); 
rectangle.draw(); 
Shape square = factoryShape.getShape("SQUARE"); 
square.draw(); 
} 
} 

Finally, we validate the output. The output would be: 

Triangle Drawn 
Rectangle Drawn 
Square Drawn 

Instead of creating an entirely new object using the new keyword, Java developers usually prefer leveraging the prototype design pattern. This is due to the virtue of performance. Prototype pattern is a commonly used creational design pattern in software development. 

Creating an object using the new keyword is a resource-intensive process. Moreover, it also impacts the performance of the created object. Contrarily, the prototype design pattern uses cloning, where a duplicate object is created on the basis of the prototype of an existing object. The prototype pattern is followed for optimizing performance of a software, app or website. 

It describes a higher-level interface that facilitates use of the subsystem. A facade design pattern applies to every abstract factory. 

Advantage: 

It shields end users from intricate system components. 

For instance, let's use the Facade Design pattern to determine how much the franchise you want to buy will cost you. 

UML Diagram:

//Franchises 
package FacadeDesignPattern; 
public interface Franchises { 
      public void franchiseOptions(); 
      public void franchiseCost(); 
}
//KFC 
public class KFC implements Franchises { 
        public void franchiseOptions() { 
               System.out.println("KFC"); 
        } 
public void franchiseCost() { 
        System.out.println("Rs 3,00,00,000"); 
        } 
} 
 
//McDonalds 
package FacadeDesignPattern; 
  
public class McDonalds implements Franchises { 
       public void franchiseOptions() { 
             System.out.println("McDonalds"); 
       } 
public void franchiseCost() { 
             System.out.println("Rs 90,00,000"); 
       } 
} 
 
//Dominos 
package FacadeDesignPattern; 
  
public class Dominos implements Franchises { 
       public void franchiseOptions() { 
            System.out.println("Dominos"); 
       } 
public void franchiseCost() { 
            System.out.println("Rs 80,00,000"); 
       } 
} 
 
//FranchiseServiceReg 
package FacadeDesignPattern; 
  
public class FranchiseServiceReg { 
       private Franchises KFC; 
       private Franchises McDonalds; 
       private Franchises Dominos; 
       public FranchiseServiceReg(){ 
              KFC = new KFC(); 
              McDonalds = new McDonalds(); 
              Dominos = new Dominos(); 
       } 
       public void BuyKFCFranchise(){ 
              KFC.franchiseOptions(); 
              KFC.franchiseCost(); 
       }  
       public void BuyMcDonaldsFranchise(){ 
              McDonalds.franchiseOptions(); 
              McDonalds.franchiseCost(); 
       } 
       public void BuyDominosFranchise(){ 
              Dominos.franchiseOptions(); 
              Dominos.franchiseCost(); 
       } 
} 
 
//Client 
package FacadeDesignPattern; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
  
public class Client { 
         private static int choice; 
         public static void main(String args[]) throws NumberFormatException, IOException{ 
                   do{ 
                              System.out.print("Welcome to Franchises Service Registration...!n"); 
                              System.out.print(" 1. KFC n"); 
                              System.out.print(" 2. McDonalds n"); 
                              System.out.print(" 3. Dominos n"); 
                              System.out.print(" 4. EXIT n"); 
                              System.out.print("Please Enter your Franchises franchiseOptions Number: "); 
                   BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
                   choice=Integer.parseInt(br.readLine()); 
                   FranchiseServiceReg sp=new FranchiseServiceReg(); 
  
         switch (choice) { 
                   case 1: { 
                           sp.BuyKFCFranchise(); 
                   } 
                   break; 
                  case 2: { 
                          sp.BuyMcDonaldsFranchise(); 
                  } 
                  break; 
                   case 3: { 
                          sp.BuyDominosFranchise(); 
                  } 
                  break; 
                  default: { 
                          System.out.println("Please Check the input and try again"); 
                  } 
          return; 
          } 
  
       }while(choice!=4); 
    } 
} 

Output: 

Welcome to Franchises Service Registration...! 
1. KFC 
2. McDonalds 
3. Dominos 
4. EXIT 
Please Enter your Franchises franchiseOptions Number: 1 
KFC 
Rs 3,00,00,000 

Both patterns make use of a dispatcher component together with Front controller and Helpers. The front controller assigns View Helpers the task of content retrieval in Service to worker. Additionally, the controller of duties including permission and authentication.

The content retrieval task is not given to helpers by the Controller in the dispatcher view. Views perform the majority of the work.

It identifies a family of functionalities, unifies them, and makes them interchangeable. The term "policy" also refers to the strategy pattern. 

Advantage: 

It is made to serve as a stand-in for sub-classes. 

We'll use a calculator as an example. There are five separate tasks we must complete. The Calculator class will include all five of these operations, and the Strategy Design Pattern will be used to run the application.

UML Diagram:

//Calculator 
package StrategyPattern; 
  
public interface Calculator { 
       public float calc(float a, float b); 
} 
 
//Add 
package StrategyPattern; 
  
public class add implements Calculator{ 
       public float calc(float a, float b) { 
              return a+b; 
       } 
} 
 
//Sub 
package StrategyPattern; 
  
public class sub implements Calculator{ 
       public float calc(float a, float b) { 
             return a-b; 
      } 
} 
 
//Mul 
package StrategyPattern; 
  
public class mul implements Calculator{ 
       public float calc(float a, float b) { 
             return a*b; 
       } 
} 
 
//Div 
package StrategyPattern; 
  
public class div implements Calculator{ 
      public float calc(float a, float b) { 
            return a/b; 
      } 
} 
 
//Mod 
package StrategyPattern; 
  
public class mod implements Calculator{ 
        public float calc(float a, float b) { 
              return a%b; 
        } 
} 
 
//Query 
package StrategyPattern; 
  
public class Query { 
      private Calculator calci; 
      public Query(Calculator calci){ 
               this.calci = calci; 
      } 
      public float executeStrategy(float num1, float num2){ 
               return calci.calc(num1, num2); 
      } 
} 
 
//Strategy 
package StrategyPattern; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
  
public class Strategy { 
         public static void main(String[] args) throws NumberFormatException, IOException { 
                  BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
                  System.out.print("Enter the first value: "); 
                  float value1=Float.parseFloat(br.readLine()); 
                  System.out.print("Enter the second value: "); 
                  float value2=Float.parseFloat(br.readLine()); 
                  Query query = new Query(new add()); 
                  System.out.println("Addition = " + query.executeStrategy(value1, value2)); 
                  query = new Query(new sub()); 
                  System.out.println("Subtraction = " + query.executeStrategy(value1, value2)); 
                  query = new Query(new mul()); 
                  System.out.println("Multiplication = " + query.executeStrategy(value1, value2)); 
                  query = new Query(new div()); 
                  System.out.println("Multiplication = " + query.executeStrategy(value1, value2)); 
                  query = new Query(new mod()); 
                  System.out.println("Multiplication = " + query.executeStrategy(value1, value2)); 
        } 
} 

The Chain of Responsibility pattern is a type of behavior where a number of objects are chained together in a specific order and given a responsibility (or request) to complete. If an object in the group can handle the specific request, it does so and sends back the appropriate response. If not, it sends the request to the next object in the group.  

It passes the invoker object a request that is contained within an object in the form of a command. The invoker object searches for the proper object that can handle the command and passes the command to the appropriate object, which then executes it. Action or Transaction are other names for it. 

Advantage: 

  • It distinguishes between the object that calls for the action and the object that executes it.

Example: This example shows a straightforward command execution cycle where the user must demonstrate turning on and off various electronic equipment in his home, such as a lightbulb and a stereo. He issues the command using a straightforward remote control as the invoker object.

//Command 
package CommandDesignPattern; 
  
interface Command { 
       public void execute(); 
} 
 
//Bulb 
package CommandDesignPattern; 
  
class Bulb { 
       public void on() { 
             System.out.println("Bulb is on"); 
       } 
public void off() { 
       System.out.println("Bulb is off"); 
       } 
} 
 
//nCommand 
package CommandDesignPattern; 
  
class nCommand implements Command { 
         Bulb light; 
         public nCommand(Bulb light) { 
                 this.light = light; 
         } 
         public void execute() { 
                 light.on(); 
         } 
} 
 
//OffCommand 
package CommandDesignPattern; 
  
class OffCommand implements Command { 
       Bulb light; 
       public OffCommand(Bulb light) { 
              this.light = light; 
       } 
       public void execute() { 
              light.off(); 
       } 
} 
 
//Stereo 
package CommandDesignPattern; 
  
class Stereo { 
       public void on() { 
              System.out.println("Stereo is on"); 
       } 
       public void off() { 
              System.out.println("Stereo is off"); 
       } 
       public void setCD() { 
              System.out.println("Stereo is set " + "for CD input"); 
       } 
       public void setDVD() { 
             System.out.println("Stereo is set" + " for DVD input"); 
       } 
       public void setRadio() { 
             System.out.println("Stereo is set" + " for Radio"); 
       } 
       public void setVolume(int volume) { 
             System.out.println("Stereo volume set" + " to " + volume); 
       } 
} 
 
//StereoOffCommand 
package CommandDesignPattern; 
  
class StereoOffCommand implements Command { 
      Stereo stereo; 
      public StereoOffCommand(Stereo stereo) { 
             this.stereo = stereo; 
      } 
      public void execute() { 
             stereo.off(); 
      } 
} 
 
//StereoOnWithCDCommand 
package CommandDesignPattern; 
  
class StereoOnWithCDCommand implements Command { 
         Stereo stereo; 
         public StereoOnWithCDCommand(Stereo stereo) { 
               this.stereo = stereo; 
         } 
         public void execute() { 
               stereo.on(); 
               stereo.setCD(); 
               stereo.setVolume(11); 
         } 
} 
 
//SimpleRemoteControl 
package CommandDesignPattern; 
  
class SimpleRemoteControl { 
       Command slot; 
       public SimpleRemoteControl() { 
       } 
       public void setCommand(Command command) { 
               slot = command; 
       } 
       public void buttonWasPressed() { 
               slot.execute(); 
       } 
} 
 
//RemoteControlTest 
package CommandDesignPattern; 
  
class RemoteControlTest { 
        public static void main(String[] args) { 
               SimpleRemoteControl remote = new SimpleRemoteControl(); 
               Bulb light = new Bulb(); 
               Stereo stereo = new Stereo(); 
               remote.setCommand(new nCommand(light)); 
               remote.buttonWasPressed(); 
               remote.setCommand(new StereoOnWithCDCommand(stereo)); 
               remote.buttonWasPressed(); 
               remote.setCommand(new StereoOffCommand(stereo)); 
               remote.buttonWasPressed(); 
       } 
} 

Output: 

Bulb is on 
Stereo is on 
Stereo is set for CD input 
Stereo volume set to 11 
Stereo is off 

A design pattern known as the null object replaces the NULL check for instance variables. Null Object reflects a do-nothing relationship rather than putting a check for a null value. When data is not accessible, it can also be used to offer default behavior.

The decorator pattern, commonly referred to as a structural pattern, is used to dynamically add new functionality to a given object. The decorator object is wrapped around the original item.

When purchasing a burger, for instance, you may choose to add more filling and sauces; but, the cost of these additions must now be factored into the final price. Customer to customer and shop to shop, personalization will vary.

There will be numerous classes created if different classes of hamburgers are created with various fillings. This issue is resolved by Decorator by dynamically expanding the functionality of a single Burger class in response to user requests.

  1. Various Java IO classes use the decorator design pattern. 
  2. Run-time use of the singleton pattern. 
  3. The calendar and different classes. 
  4. The factory pattern, which is utilized in conjunction with a number of immutable classes, including Boolean. For example, function valueOf(). 
  5. Swing and numerous event listener frameworks use the observer design. 

This along with similar questions on Java Design Pattern interviews is a regular feature in Java Design Pattern Interviews, be ready to have a complete explanation.

The MVC (Model View Controller) design pattern is described as follows: 

Models serve as the application's blueprints for all the objects that will be used in it. Views are used to represent how the data and information included in the models are presented.

Both the Models and the Views are controlled by and acted upon by the Controllers. They act as a bridge connecting the Models and Views. Models can be created, updated, and deleted by controllers. They fill them up with data and then transmit it to the views so the user can see it.

Advantages: 

  • For a model, it supports numerous views. 
  • To set and print the student data, for instance, we'll use the MVC Design Pattern. 

//MVC pattern 
package MVCDesignPattern;   
public class MVCPattern { 
public static void main(String[] args){ 
              Student model = retriveStudentFromDatabase(); 
              StudentView view = new StudentView(); 
              StudentController controller = new StudentController(model, view); 
              controller.updateView(); 
              controller.setStudentName("Rajat Shukla"); 
              controller.updateView(); 
       } 
       private static Student retriveStudentFromDatabase(){ 
              Student student = new Student(); 
              student.setName("Ram Kumar"); 
              student.setRollNo("21CSE987"); 
              return student; 
       } 
} 
 
//Student 
package MVCDesignPattern; 
public class Student { 
      private String rNo; 
      private String name; 
      public String getRollNo(){ 
            return rollNo; 
      } 
      public void setRollNo(String rollNo){ 
            this.rollNo = rollNo; 
      } 
      public String getName(){ 
            return name; 
      } 
      public void setName(String name){ 
           this.name = name; 
      } 
} 
  
//StudentController 
  
package MVCDesignPattern; 
  
public class StudentController { 
       private Student model; 
       private StudentView view; 
       public StudentController(Student model, StudentView view){ 
              this.model = model; 
              this.view = view; 
       } 
       public void setStudentName(String name){ 
              model.setName(name); 
       } 
       public String getStudentName(){ 
              return model.getName(); 
       } 
       public void setStudentRollNo(String rollNo){ 
             model.setRollNo(rollNo); 
       } 
       public String getStudentRollNo(){ 
             return model.getRollNo(); 
       } 
       public void updateView(){ 
             view.printStudentDetails(model.getName(), model.getRollNo()); 
       } 
} 
 
//StudentView 
package MVCDesignPattern; 
  
public class StudentView { 
        public void printStudentDetails(String studentName, String studentRollNo){ 
               System.out.println("Student: "); 
               System.out.println("Name: " + studentName); 
               System.out.println("Roll No: " + studentRollNo); 
        } 
} 

Output: 

Student: 
Name: Ram Kumar 
Roll No: 21CSE987 
Student: 
Name: Rajat Shukla 
Roll No: 21CSE988

Transfer object is a straightforward Java class that only has fields and no business logic. They have accessor methods (getter and setters) to access fields and are serializable POJO classes. These classes don't have to match business objects; they just transport data between levels. Transfer objects often group arguments for method calls.

This is one of the most frequently asked Java Design Pattern Interview questions for experienced professionals.

Often, Java developers might be caught in the dilemma to choose between an abstract class and an interface. For such scenarios, you must know the basic differences between the two so that you can choose the one perfect for your requirements. These points are: 

  • Java supports extending a single class only, whereas a single class can implement multiple interfaces. Interfaces are defined in the form of adjectives. That’s because they represent behavior. If an abstract class represents behavior, it can’t behave in two ways, i.e., an abstract class can never be Runnable and Serializable at the same time. 
  • An abstract class is faster than an interface. 
  • When common behavior across the inheritance hierarchy can be optimized, i.e., coded better than the abstract class is the ideal choice. In certain scenarios, both an abstract class and an interface can be used together. Here, the function is defined in the interface, and the default functionality is in the abstract class. 

In concurrent Java applications, FutureTask represents a cancellable asynchronous computation. FutureTask provides a base implementation for the Future interface. It is a pre-defined Java class that contains various methods for: 

  • Starting and canceling computations. 
  • Queries to check the status of the computations. 
  • Retrieving the results of the computations. 

You can wrap a Callable or Runnable object using a FutureTask object. It can be submitted to an Executor because FutureTask also implements Runnable. 

Note that it is only possible to retrieve the result of a computation that is completed. Trying to fetch the result of an uncompleted computation results in blocking of the get methods. 

Java being a multi-threaded programming language facilitates concurrent design or concurrent programming. While designing a concurrent system, it is important to ensure immutability, using local variables, and thread-safety. Instance or static variables must be avoided. 

A single class can execute multiple threads, so it’s suitable that every thread has its own data to work with so that it doesn’t interfere with other data and has minimal synchronization at the start of the pipeline. 

This is one of the trickiest software design pattern interview questions that might also require coding. Therefore, you need to understand important aspects of concurrency, including atomicity, deadlock, memory interference, race condition, and ThreadLocal variables.

Both concurrent and synchronized collections are ideal for concurrent and multi-threaded access. The difference is that the concurrent collection is more scalable. 

Releases prior to Java 1.5 had only synchronized collection. It worked fine and also provided thread-safety. However, when multiple threads accessed it, the scalability of the system goes down greatly. 

Concurrent collections like ConcurrentHashMap were introduced in Java 5. These collections not only provide thread-safety but also improved scalability by leveraging techniques like partitioning internal tables and lock stripping. 

Stack is integral to threads. Hence, it is important to learn how stack works to better understand concurrency and multi-threading. Both stack and heap are specific types of memories. 

Every thread has its own stack that stores call stack, local variables, and method parameters. Variables stored in the stack of one thread are not visible to one another. Unlike a thread, a heap is a common memory space shared by all the threads. 

Objects are created inside the heap. Thread cache values from the heap into their stack for improving performance. However, if the variable is modified by many threads, issues can arise. This issue is resolved by the introduction of volatile variables. They make the threads read the value of the variable from main memory. 

Deadlock occurs when two threads start waiting for each other to perform something and then they do nothing. This makes the program execution halt and the software hangs. To understand how to prevent a deadlock in Java, you need to understand four conditions that must be true for a deadlock to occur, which are: 

  1. Circular Wait - A process waits for a resource that is being held by another process, which is waiting for it to release its resource. 
  2. Hold and Wait - A process is holding at least one resource and is requesting one or more resources held by another process(es). 
  3. Mutual Exclusion - At least one resource must be held in a non-shareable mode and only a single process can use the resource at a given time. 
  4. No Preemption - The OS must not deallocate resources after allocation. They must be released voluntarily by the processes. 

The best way to avoid a deadlock is to prevent Circular Wait. One way to do this is by acquiring locks in a particular order and then releasing them in the reverse order. 

We create a thread-safe singleton class to facilitate object initialization when multiple threads are available. We can do so in many ways. Let’s learn about some of them: 

  • Static field initialization 

The Classloader guarantees the initialization of instances at the time of class loading. Thus, another way to create a thread-safe singleton class is to develop the instance during class loading. For this, you need to use static fields. 

Example: 

public class ThreadSafeSingleton{ 
      private static final ThreadSafeSingleton INSTANCE = new ThreadSafeSingleton(); 
      private ThreadSafeSingleton(){ } 
      public static ThreadSafeSingleton getInstance(){ 
          return INSTANCE; 
      } 
      public void display(){ 
          System.out.println("Thread-safe Singleton"); 
      } 
   } 
   ThreadSafeSingleton.getInstance().display(); 

Note: The instance is invisible during the creation. 

  • Synchronized Keyword 

Another way to implement Singleton design patterns in Java is by using the synchronized keyword. We can use the synchronized keyword with the getInstance method. 

Example: 

public class ThreadSafeSingleton 
   { 
    // Creating private instance to make it accessible only by getInstance() method 
    private static ThreadSafeSingleton instance; 
    private ThreadSafeSingleton() 
    { 
      // Making constructor private so that objects cant be initialized outside the class 
    } 
    //synchronized getInstance method 
    synchronized public static ThreadSafeSingleton getInstance(){ 
      if (this.instance == null) 
      { 
        // if instance is null, initialize 
        this.instance = new ThreadSafeSingleton(); 
      } 
      return this.instance; 
    } 
   } 

You achieve lazy initialization in this method and the object initialization is thread-safe due to the use of the synchronized keyword. Because of the same reason, the performance can get affected in case of multiple threads. 

  • Enums 

Enums are finalized by default. Thus, they help in avoiding many initializations during serialization in Java. This is the easiest way to implement a thread-safe singleton class in Java since the object-oriented programming language provides internal synchronization support. 

Example: 

public enum ThreadSafeSingleton{ 
TSSINGLETON_INSTANCE; 
public void display(){ 
System.out.println("Thread-safe singleton is ready"); 
} 
} 

To invoke the methods of the singleton class, we can use: 

ThreadSafeSingleton.TSSINGLETON_INSTANCE.show(); 

To generate the pyramid pattern on the screen, we need to leverage the concept of looping and define a class PyramidPattern: 

public class PyramidPattern 
{ 
  public static void printPyramid (int n) 
  { 
    for (int i = 0; i < n; i++) 
      {// for number of rows  
for (int j = n - i; j > 1; j--) 
  { 
    System.out.print (" ");//print space 
  } 
//for number of columns 
for (int j = 0; j <= i; j++) 
  { 
    System.out.print ("* ");// print star 
  } 
//end-line after every row 
System.out.println (); 
      } 
  } 
  public static void main (String args[]) 
  { 
    printPyramid (5);//Print Pyramid stars of 5 rows 
  } 
} 

The output of the Java program will be: 

       * 

      * * 

     * * * 

    * * * * 

   * * * * *