Design Patterns in Java
Design Patterns in Java
https://refactoring.guru/design-patterns/java
1. Singleton
Singleton is a creational design pattern that lets you ensure that a class
has only one instance while providing a global access point to this
instance.
https://refactoring.guru/design-patterns/singleton
Singleton works on the concept of one and only one instance of the
object, which results in the global control of a resource. In simple
words, the Singleton design pattern ensures that only one instance of the
class will be created and that instance will have global access within the
application.
private SingletonClass() {
// private constructor to prevent instantiation from outside
}
As you can see below controller class and when we send a request via
Postman result will be one and the same instance.
@RestController
@RequestMapping("/api")
public class SingletonController {
@GetMapping("/singleton")
public String getSingleton() {
return "This is a singleton instance: " +
singletonClass.toString();
}
When you want to ensure that only one instance of a class exists, for
example, a single database object shared by different parts of the
program, you should use the Singleton design pattern.
2. Factory
void processPayment();
}
@Service
public class CreditCardPaymentProcessor implements
PaymentProcessor {
@Override
public void processPayment() {
// Credit card payment transactions
}
}
@Service
public class PaypalPaymentProcessor implements
PaymentProcessor {
@Override
public void processPayment() {
// Paypal card payment transactions
}
}
@Component
public class PaymentProcessorFactory {
public PaymentProcessorFactory(CreditCardPaymentProcessor
creditCardPaymentProcessor,
PaypalPaymentProcessor
paypalPaymentProcessor) {
this.creditCardPaymentProcessor =
creditCardPaymentProcessor;
this.paypalPaymentProcessor = paypalPaymentProcessor;
}
3. Abstract Factory
//Factory Classes
public interface ProductFactory {
Product createProduct();
}
//Product Classes
public interface Product {
String getName();
}
@Override
public String getName() {
return "Product A";
}
}
@Override
public String getName() {
return "Product B";
}
}
The Abstract Factory pattern is helpful when your code needs to deal
with different groups of related items, but you want to avoid
depending on the specific types of those items. These types might not be
known in advance or you might want to keep room for adding more types
in the future.
4. Builder
@Builder
@Getter
@Setter
public class Beer {
//required
private String name;
private double drinkSize;
private double alcoholPercentage;
private double price;
// Other attributes
private String brewery; // The brewery that produces the
beer.
private String countryOfOrigin; // The country where the beer
is originally from.
private String description; // A brief description of the
beer's characteristics.
private String packaging; // The packaging type (bottle,
can, draft, etc.).
private String servingTemperature; // The recommended
serving temperature.
private String foodPairing; // Foods that pair well with this
beer.
@RestController
@RequestMapping("/api/beers")
public class BeerController {
@GetMapping("/basic")
public String createStandardBeer() {
Beer beer = Beer.builder()
.name("Standard Beer")
.drinkSize(500)
.alcoholPercentage(5.0)
.price(5.99)
.build();
@GetMapping("/premium")
public String createPremiumBeer() {
Beer beer = Beer.builder()
.name("Sample Beer")
.drinkSize(330)
.alcoholPercentage(5.0)
.price(10.99)
.brewery("Crafty Brews")
.countryOfOrigin("United States")
.description("A refreshing lager with a smooth taste.")
.packaging("Bottle")
.servingTemperature("4-6°C")
.foodPairing("Pairs well with grilled chicken and
salads.")
.build();
}
Advantages
Disadvantages
5. Prototype
designpatterns
└── creational
└── prototype
├── controller
│ └── TreeController.java
├── model
│ ├── Tree.java
│ ├── PlasticTree.java
│ └── PineTree.java
└── PrototypeDemoApplication.java
//Abstract Class
@Getter
@Setter
public abstract class Tree implements Cloneable {
private String type;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public PineTree() {
setType("Pine Tree");
}
@Override
public void copy() {
//implementation
}
}
@Override
public void copy() {
//implementation
}
@RestController
@RequestMapping("/api/trees")
public class TreeController {
@GetMapping("/plastic")
public String createPlasticTree() {
Tree plasticTree = new PlasticTree();
return "Created: " + plasticTree.getType();
}
@GetMapping("/pine")
public String createPineTree() {
Tree pineTree = new PineTree();
return "Created: " + pineTree.getType();
}
}
The Prototype pattern can be useful when the new object we need to
create exhibits only minor differences from an existing one. So,
instead of making completely new objects each time, we can set up
examples with the right settings in advance, and then copy them when we
need more.