Javatpoint Logo
Javatpoint Logo

Java Generics Design Patterns

Java generics introduced the idea of parameterized types, which completely changed how programmers create Java code. Because of this, programming has entered a new era in which Java code is shorter, more adaptable, and type-safe. To accomplish these advantages, several design patterns make use of Java generics. In this section, we will discuss some of the popular design patterns for Java generics.

Factory Pattern

A creational pattern called the Factory Pattern offers a means to generate items without having to identify the precise type of object that will be produced. Instead, based on the input parameters it gets, the factory generates the object. A generic factory that can make objects of any class that implements a particular interface can be made using Java generics.

The following code demonstrates the use of generics in the Factory Pattern:

FactoryPatternExample.java

Output:

Driving a car...
Driving a truck...

In this example, the classes Car and Truck both implement the Vehicle interface. The next step is to construct the generic factory class VehicleFactory, which accepts a type argument T and mandates that it extend the Vehicle interface. A new instance of the class supplied as a parameter is created and returned by the createVehicle function of the VehicleFactory class. The VehicleFactory classes for cars and trucks are created and used to produce instances of the corresponding classes in the main method.

Strategy Pattern

A behavioural pattern called the Strategy Pattern makes it possible to choose an algorithm at runtime. By developing a generic interface that describes the algorithm and a set of classes that implement the interface for various algorithm implementations, this pattern can be accomplished using Java generics.

The following code demonstrates the use of generics in the Strategy Pattern:

StrategyPatternExample.java

Output:

Sorting using Bubble Sort...
Sorting using Quick Sort...
Sorting using Merge Sort...

As we can see, the Sorter class is using the selected sorting strategy to sort the array.

In this example, we have a function called sort() on an interface called SortingStrategy. This interface is implemented by the three classes BubbleSort, QuickSort, and MergeSort, each of which has a unique sort() function implementation.

Additionally, there is a class called Sorter, which has a strategy private SortingStrategy variable. The sort() method of this class calls the sort() method of the selected sorting strategy, while the setStrategy() function sets the sorting strategy.

We build an array of numbers and a Sorter object in the main() method. Using the setStrategy() function, we set the sorting strategy to BubbleSort, QuickSort, and MergeSort, and then we run the sort() method on the Sorter object.

By using the Strategy pattern, we can easily switch between different sorting algorithms without changing the Sorter class's implementation.

Bridge Pattern

When an abstraction and its implementation are separated using the Bridge design, they can change independently. When a class's implementation needs to be changed without impacting its interface or when you wish to shield customers from the implementation's specifics, this design pattern might be helpful. Generics can be used to implement the Bridge pattern by creating a parameterized interface or abstract class that defines the implementation and a parameterized implementation class that defines the abstraction. Specifying the kinds of objects that are being implemented and abstracted using the type parameter is possible.

Adapter Pattern

The interface of a class is transformed into another interface that clients anticipate using the adapter technique. This approach can be helpful if one of your classes offers a specific capability but has an interface that is incompatible with the rest of your codebase. Generics can be used to implement the Adapter pattern by creating an abstract class or parameterized interface that specifies the desired interface and a parameterized adapter class that converts the incompatible class to the desired interface. The types of objects that are being altered can be specified using the type argument.

Visitor Pattern

The algorithm and the object structure it uses are kept apart using the Visitor pattern. When you have a complicated object structure and wish to execute various operations on its components without changing the classes that define the structure, you may find this pattern to be helpful. By creating a parameterized interface or abstract class that describes the operations and a parameterized visitor class that implements the operations for particular sorts of objects in the structure, the Visitor pattern can be implemented using generics. The sorts of items that the visitor can manipulate can be specified using the type argument.

The Builder Pattern

The Builder Pattern is a creational pattern that distinguishes between an object's actual construction and its representation. This pattern is helpful when you need to divide the development of an object that needs several phases into smaller, more manageable steps in order to make the process more straightforward.

To generate complicated objects with many types of parameters in Java, the Builder Pattern is frequently combined with Generics. A universal Builder class that may be used to construct objects of any type is the goal. The build function of the Builder class would return the finished object in addition to methods for setting the various properties of the object that were being built.

Here is an example implementation of the Builder Pattern in Java:

BuilderPatternExample.java

Output:

Make: Toyota
Model: Camry
Year: 2018
Color: White
Mileage: 40000
Transmission: Automatic

In this illustration, the make, model, year, colour, mileage, and gearbox of the car are all represented by various fields in the Car class. Additionally, we have a nested CarBuilder class that enables us to construct a Car object in a way that is easier to read and maintain.

Creating an instance of the CarBuilder class and calling its setter methods to set the desired properties of the Car object we want to build are the initial steps in applying the builder pattern. In order to generate the Car object with the necessary properties, we finally execute the build() method. This method makes the creation of objects clearer and easier to read, especially when working with classes that contain a lot of properties.

Conclusion

A strong and adaptable method for producing reused, type-safe code is provided by Java generics. The full power of generics may be utilised to produce more modular, adaptable, and maintainable code by leveraging generics design patterns. The design patterns that were discussed in this article are only a few instances of how generics can be utilised to address typical programming issues. Many more design patterns can be applied using generics, and with a little imagination, you can create your own.







Youtube For Videos Join Our Youtube Channel: Join Now

Feedback


Help Others, Please Share

facebook twitter pinterest

Learn Latest Tutorials


Preparation


Trending Technologies


B.Tech / MCA