MockIT logo on dark background.
Schedule interviewBlog
Log In
MockIT logo on dark background.
MockIT logo.

Do you get the feeling that no one is reading your CV? Not getting invitations to recruitment interviews?

Test your technical skills and let MockIT help find you a job in IT!

Book an interview
Back

Java Design Patterns Basics + Sample Interview Questions

90% of Java interviews include questions about design patterns. In this article, I will cover the most popular ones and point out the interview questions you might encounter during a recruitment interview.

Adrian Miś

Senior Java Developer - RightHub


July 17, 2024

Intro

Design patterns constitute the foundation of well-designed software. They are ready-made solutions to recurring design problems that can be applied in various contexts during software creation. Undoubtedly, every Java programmer should use them to create efficient programming solutions.

In this article, we will look at the basic yet most popular design patterns in Java. We will discuss their categories and present practical examples of their application. The information I tried to include here I personally used in many job interviews that landed me jobs, so it can help you too :) At the end, I will present some sample interview questions that may appear in a job interview.

What are design patterns?

These are descriptions or templates for solving a problem that occurs in a specific design context. They have been collected, classified, and documented by experts in their fields to help developers maintain high-quality code, including improving its readability and flexibility. Implementing design patterns should facilitate and optimize code rather than unnecessarily complicate the project.

Goals of design patterns

Facilitating communication: providing a common language for developers, making communication and understanding easier among team members.

Improving the design process: with patterns, you can quickly find the right solution to a problem, speeding up the software design process.

Increasing code quality: using proven design patterns leads to more understandable and maintainable code.

Categories of design patterns

Creational Patterns

Creational patterns focus on the process of creating objects. Their goal is to abstract the instantiation process, allowing for dynamic and flexible object creation, thus facilitating code reuse.

Singleton

Ensures that a class has only one instance and a global access point to it.

Factory Method

Defines an interface for creating objects but allows subclasses to decide which class to instantiate.

Abstract Factory

Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Structural Patterns

Structural patterns are about class and object composition, focusing on simplifying designs by solving structure-related problems.

Adapter

Transforms an interface into another interface expected by a client, enabling cooperation between classes that otherwise could not work together.

Bridge

Separates an abstraction from its implementation, allowing both to be developed independently.

Composite

Composes objects into tree structures to represent part-whole hierarchies, enabling clients to treat individual objects and their compositions uniformly.

Behavioral Patterns

Behavioral patterns focus on communication between objects and algorithms, defining how objects collaborate and communicate with each other.

Observer

Defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated.

Strategy

Defines a family of algorithms, encapsulates each one, and makes them interchangeable, allowing the algorithm used by a client to be changed dynamically.

Command

Turns a request into an object, allowing for parameterization of objects with different requests, queuing or logging requests, and supporting undoable operations.

Basic Java Design Patterns

Here, I will introduce you to some design patterns that are really easy to learn and understand, and thanks to them, you will definitely shine in an interview ;)

Singleton

Belongs to the category of creational patterns and its purpose is to ensure that a given class has only one instance and provides a global access point to that instance. It is used in situations where a single, shared data source or coordination point is necessary, e.g., in logging systems, configuration management, database connections, or managing external resources.

Key Features

Single instance: guarantees that the class has only one instance.

Global access: allows global access to that instance.

Instance control: ensures control over the instantiation process.

Implementation in Java

public class SingleInstance { private static SingleInstance instance; // Private constructor prevents the creation of external objects. private SingleInstance() { } // Public method that returns a single instance of Singleton public static synchronized SingleInstance getInstance() { if (instance == null) { instance = new SingleInstance(); } return instance; } }

In the above example:

Private constructor: prevents creating instances from outside.

Static getInstance method: provides a global access point to the only instance. The synchronized keyword ensures that the method is thread-safe.

Configuration management

Singleton can be used to store and share application configuration settings, ensuring that all parts of the application use the same settings.

public class ConfigurationManager { private static ConfigurationManager instance; private Properties config; private ConfigurationManager() { config = new Properties(); // Load properties from a file // config.load(new FileInputStream("config.properties")); } public static synchronized ConfigurationManager getInstance() { if (instance == null) { instance = new ConfigurationManager(); } return instance; } public String getProperty(String key) { return config.getProperty(key); } }

Singleton in Spring Framework

The Spring Framework automatically manages beans in the application context as singletons. By default, every bean in Spring is a singleton, meaning that Spring manages a single instance of the bean throughout the entire application context.

An example of defining a bean as a singleton in Spring configuration:

@Configuration public class AppConfig { @Bean public MyService myService() { return new MyService(); } }

In Spring, you can always create a Singleton in a very simple way, just add the @Repository, @Service, @Controller, @Component annotation, and the Spring container will take care of the rest.

Advantages of Singleton

Global access: allows access to the same instance from anywhere in the application.

Resource control: provides centralized management of resources such as configurations or database connections.

Ease of implementation: simple and intuitive design.

Disadvantages of Singleton

Testing problems: difficulty in unit testing due to global state, which can be hard to reset between tests.

Prone to misuse: can lead to overuse of global state, complicating code maintenance and understanding.

Multithreading: can be problematic in multithreaded environments if not implemented correctly (synchronization mechanisms are necessary).

Summary

Singleton is a key tool in a developer's arsenal, offering a simple way to manage unique instances in an application. While it has its limitations and potential drawbacks, its proper use can significantly simplify resource and configuration management, especially in complex systems.In the Spring Framework, managing singletons is even easier thanks to automatic bean management, further enhancing code efficiency and clarity.

Wrapper Pattern

Wrapper is a structural pattern that serves to wrap one interface in another, compatible interface. It is used in situations where there are differences in interfaces or expectations between different parts of the system or modules.

Usage in Java: Integer vs int

In Java, Integer is an example of a Wrapper. Integer is a class that wraps the primitive type int. Here are the differences between them:

int: primitive type representing integers (e.g., 1, 2, -3).

Integer: wrapper class for int that provides additional functionalities such as helper methods, the ability to use in generic contexts, and automatic conversion to/from primitive type. It's also possible to store null here and perform functions like equals() or toString().

int primitiveInt = 10; Integer wrappedInt = new Integer(10); // Can be used in a generic context List<Integer> integerList = new ArrayList<>(); integerList.add(1); integerList.add(2); // Automatic conversion between int and Integer int intValue = wrappedInt.intValue();

Creating a simple Wrapper in a business context

Let's assume we have two unrelated objects in our application that must be treated as one from a business perspective, for example, customer and order. We can use a Wrapper to wrap these two objects into one.
public class CustomerOrderWrapper { private Customer customer; private Order order; public CustomerOrderWrapper(Customer customer, Order order) { this.customer = customer; this.order = order; } public Customer getCustomer() { return customer; } public Order getOrder() { return order; } }

In the above example, CustomerOrderWrapper wraps the customer and order objects into one wrapper, allowing operations on both objects simultaneously in the application.

Advantages of Wrappers

Interface adaptation: allows adapting existing interfaces or classes to new requirements.

Ease of using different data types: Wrappers allow for manipulating data in a more flexible way, including conversion between different types.

Disadvantages of Wrappers

Additional level of abstraction: may introduce an additional level of abstraction and complexity in the code.

Overhead associated with wrapping: may introduce a slight performance overhead associated with creating and managing wrapper objects.

Summary

Wrapper is used to adapt and wrap existing interfaces or objects in a different way to meet new application requirements. In the context of Java, Integer is an example of a wrapper for the primitive type int, and sample usage may include wrapping unrelated business objects into a single data structure.

Iterator Pattern

Iterator is a behavioral pattern that allows sequential access to collection elements without revealing its internal representation. Iterator allows iteration over collection elements and operating on them without knowing the implementation details of the collection.

Usage in Java (collections)

In Java, Iterator is commonly used in collection interfaces such as List, Set, or Map. Here's how to use Iterator in practice:
List<String> list = new ArrayList<>(); list.add("Element 1"); list.add("Element 2"); list.add("Element 3"); // Obtaining an iterator Iterator<String> iterator = list.iterator(); // Iteration and display of elements while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); }

In the above example, iterator() returns an Iterator for the ArrayList, which can be used to sequentially traverse through the list elements using hasNext() and next() methods

Implementing your own Iterator

We can also create our own Iterator for a custom collection. Here's an example of a simple Iterator for a custom class CustomCollection:
public class CustomCollection { private String[] elements = {"A", "B", "C"}; public Iterator<String> iterator() { return new CustomIterator(); } private class CustomIterator implements Iterator<String> { private int index = 0; @Override public boolean hasNext() { return index < elements.length; } @Override public String next() { if (!hasNext()) { throw new NoSuchElementException(); } return elements[index++]; } } }

In this example, CustomCollection contains a custom array elements, and CustomIterator is a nested class implementing the Iterator interface. This allows us to iterate over CustomCollection elements just like standard collections.

Advantages of Iterator

Separation of interface from implementation: Iterator allows access to collection elements without revealing details of its structure.

Universality: allows applying the same iterative operations for different types of collections.

Application of Iterator

Browsing and operating on collection elements: Iterator is used wherever we need sequential access to collection elements regardless of its specific implementation.

Multiple data processing: Iterator allows multiple passes through the same data without the need to copy or modify the collection structure.

Summary

The Iterator pattern is extremely useful in object-oriented programming, enabling safe and ordered access to collection elements. Its implementation in Java is common in collection interfaces, which makes it easier for programmers to work with different data types.Thanks to Iterator, we can create more flexible and modular applications that are easier to maintain and develop. It's one of those patterns that you use without realizing you're actually doing it.

Sample Interview Questions

  • What is a Singleton? How to implement it? What are its advantages and disadvantages?

  • What is the Factory Method pattern? What are its applications?

  • What's the difference between Factory Method and Abstract Factory patterns?

  • What are structural patterns? Give examples.

  • Describe the MVC (Model-View-Controller) pattern. What are its advantages?

  • What are behavioral patterns? Give examples and describe their applications.

  • What are the applications of the Builder pattern? How to implement it in practice?

  • Using which library can we quickly and easily use the Builder pattern?

  • What is the Proxy pattern? What are its applications?

  • What are the main differences between Immutable and Mutable patterns?

  • What are the most common patterns in Spring? Give examples and explain how they work.

Summary

I hope that along with reading the article, understanding of this important, but not so difficult topic will increase.

If you tie your career to programming, design patterns will accompany you until its end, so it's worth spending some time learning them, as you will use them in your daily work while coding.

In technical interviews for Developer positions, especially Java ones, questions about design patterns occur in 90% of cases, so it's worth learning ;)


You may also be interested in

© 2024 MockIT