From 981e7a85bec27547749260df4eab8aed98938b28 Mon Sep 17 00:00:00 2001 From: Subhatav Dhali Date: Sat, 2 Nov 2024 20:17:46 +0530 Subject: [PATCH 1/6] Implement the Factory Method Design Pattern --- .../creational/factory/BronzeCoin.java | 25 +++++++++++++++++++ .../creational/factory/CoinFactory.java | 18 +++++++++++++ src/practice/creational/factory/CoinType.java | 17 +++++++++++++ .../creational/factory/FactoryDemo.java | 21 ++++++++++++++++ .../creational/factory/MassFactory.java | 25 +++++++++++++++++++ .../creational/factory/MetalCoin.java | 6 +++++ .../creational/factory/RareFactory.java | 25 +++++++++++++++++++ .../creational/factory/SilverCoin.java | 25 +++++++++++++++++++ 8 files changed, 162 insertions(+) create mode 100644 src/practice/creational/factory/BronzeCoin.java create mode 100644 src/practice/creational/factory/CoinFactory.java create mode 100644 src/practice/creational/factory/CoinType.java create mode 100644 src/practice/creational/factory/FactoryDemo.java create mode 100644 src/practice/creational/factory/MassFactory.java create mode 100644 src/practice/creational/factory/MetalCoin.java create mode 100644 src/practice/creational/factory/RareFactory.java create mode 100644 src/practice/creational/factory/SilverCoin.java diff --git a/src/practice/creational/factory/BronzeCoin.java b/src/practice/creational/factory/BronzeCoin.java new file mode 100644 index 0000000..2d379de --- /dev/null +++ b/src/practice/creational/factory/BronzeCoin.java @@ -0,0 +1,25 @@ +package practice.creational.factory; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.extern.java.Log; + +@Log +@ToString +@EqualsAndHashCode +@RequiredArgsConstructor +public final class BronzeCoin implements MetalCoin { + + private static final Integer PRINCIPAL_COST = 2_500; + + @NonNull + private final Float demandFactor; // Price MULTIPLIER + + @Override + public void printWorth() { + final var value = (PRINCIPAL_COST * demandFactor) + " INR"; + log.info("Monetary WORTH of BRONZE Coin => " + value); + } +} diff --git a/src/practice/creational/factory/CoinFactory.java b/src/practice/creational/factory/CoinFactory.java new file mode 100644 index 0000000..fcb6627 --- /dev/null +++ b/src/practice/creational/factory/CoinFactory.java @@ -0,0 +1,18 @@ +package practice.creational.factory; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +public abstract sealed class CoinFactory permits MassFactory, RareFactory { + + protected abstract Float getDemandFactor(); // Get SPECIFIC multiplier + + public MetalCoin mintCoin(@NonNull final CoinType coinType) { + var mintedCoin = coinType.getCreator().apply(getDemandFactor()); + log.info("CATEGORY of Minted COIN => [" + mintedCoin + "]"); + return mintedCoin; // Return the SPECIFIC category of minted COIN + } +} diff --git a/src/practice/creational/factory/CoinType.java b/src/practice/creational/factory/CoinType.java new file mode 100644 index 0000000..56efb9c --- /dev/null +++ b/src/practice/creational/factory/CoinType.java @@ -0,0 +1,17 @@ +package practice.creational.factory; + +import java.util.function.Function; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum CoinType { + + BRONZE(BronzeCoin::new), // Holds CONSTRUCTOR + SILVER(SilverCoin::new); // Holds CONSTRUCTOR + + @NonNull + private final Function creator; +} diff --git a/src/practice/creational/factory/FactoryDemo.java b/src/practice/creational/factory/FactoryDemo.java new file mode 100644 index 0000000..9c1d679 --- /dev/null +++ b/src/practice/creational/factory/FactoryDemo.java @@ -0,0 +1,21 @@ +package practice.creational.factory; + +import java.util.List; + +/** + * Example of Factory Method Design Pattern + */ +public final class FactoryDemo { + + public static void main(final String... arguments) { + + createCoinMints().forEach(coinFactory -> { + coinFactory.mintCoin(CoinType.BRONZE).printWorth(); + coinFactory.mintCoin(CoinType.SILVER).printWorth(); + }); + } + + private static List createCoinMints() { + return List.of(new MassFactory(), new RareFactory()); + } +} diff --git a/src/practice/creational/factory/MassFactory.java b/src/practice/creational/factory/MassFactory.java new file mode 100644 index 0000000..d947369 --- /dev/null +++ b/src/practice/creational/factory/MassFactory.java @@ -0,0 +1,25 @@ +package practice.creational.factory; + +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.ToString; +import lombok.extern.java.Log; + +@Log +@ToString +@NoArgsConstructor +public final class MassFactory extends CoinFactory { + + private static final Float DEMAND_FACTOR = 1.2F; + + @Override + protected Float getDemandFactor() { + return DEMAND_FACTOR; + } + + @Override + public MetalCoin mintCoin(@NonNull final CoinType coinType) { + log.info("Current FACTORY for MINT => [" + this + "]"); + return super.mintCoin(coinType); // Get CURRENT minted COIN + } +} diff --git a/src/practice/creational/factory/MetalCoin.java b/src/practice/creational/factory/MetalCoin.java new file mode 100644 index 0000000..74a887c --- /dev/null +++ b/src/practice/creational/factory/MetalCoin.java @@ -0,0 +1,6 @@ +package practice.creational.factory; + +public sealed interface MetalCoin permits BronzeCoin, SilverCoin { + + void printWorth(); // Prints monetary WORTH of minted Metal COIN +} diff --git a/src/practice/creational/factory/RareFactory.java b/src/practice/creational/factory/RareFactory.java new file mode 100644 index 0000000..4129e88 --- /dev/null +++ b/src/practice/creational/factory/RareFactory.java @@ -0,0 +1,25 @@ +package practice.creational.factory; + +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.ToString; +import lombok.extern.java.Log; + +@Log +@ToString +@NoArgsConstructor +public final class RareFactory extends CoinFactory { + + private static final Float DEMAND_FACTOR = 4.8F; + + @Override + protected Float getDemandFactor() { + return DEMAND_FACTOR; + } + + @Override + public MetalCoin mintCoin(@NonNull final CoinType coinType) { + log.info("Current FACTORY for MINT => [" + this + "]"); + return super.mintCoin(coinType); // Get CURRENT minted COIN + } +} diff --git a/src/practice/creational/factory/SilverCoin.java b/src/practice/creational/factory/SilverCoin.java new file mode 100644 index 0000000..5d34734 --- /dev/null +++ b/src/practice/creational/factory/SilverCoin.java @@ -0,0 +1,25 @@ +package practice.creational.factory; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.extern.java.Log; + +@Log +@ToString +@EqualsAndHashCode +@RequiredArgsConstructor +public final class SilverCoin implements MetalCoin { + + private static final Integer PRINCIPAL_COST = 5_000; + + @NonNull + private final Float demandFactor; // Price MULTIPLIER + + @Override + public void printWorth() { + final var value = (PRINCIPAL_COST * demandFactor) + " INR"; + log.info("Monetary WORTH of SILVER Coin => " + value); + } +} From b236a35f959d368b69193f2ef267b47460d0db72 Mon Sep 17 00:00:00 2001 From: Subhatav Dhali Date: Sat, 2 Nov 2024 20:32:58 +0530 Subject: [PATCH 2/6] Implement the Abstract Factory Design Pattern --- .../creational/notional/AbstractDemo.java | 25 +++++++++++++++++++ .../creational/notional/FactoryMaker.java | 21 ++++++++++++++++ .../creational/notional/FactoryType.java | 20 +++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 src/practice/creational/notional/AbstractDemo.java create mode 100644 src/practice/creational/notional/FactoryMaker.java create mode 100644 src/practice/creational/notional/FactoryType.java diff --git a/src/practice/creational/notional/AbstractDemo.java b/src/practice/creational/notional/AbstractDemo.java new file mode 100644 index 0000000..b5e9848 --- /dev/null +++ b/src/practice/creational/notional/AbstractDemo.java @@ -0,0 +1,25 @@ +package practice.creational.notional; + +import java.util.Arrays; +import java.util.List; +import practice.creational.factory.CoinFactory; +import practice.creational.factory.CoinType; + +/** + * Example of Abstract Factory Design Pattern + */ +public final class AbstractDemo { + + public static void main(final String... arguments) { + + createCoinFactories().forEach(coinFactory -> { + coinFactory.mintCoin(CoinType.BRONZE).printWorth(); + coinFactory.mintCoin(CoinType.SILVER).printWorth(); + }); + } + + private static List createCoinFactories() { + final var factoryTypes = FactoryType.values(); // LIST of Factory TYPES + return Arrays.stream(factoryTypes).map(FactoryMaker::makeMint).toList(); + } +} diff --git a/src/practice/creational/notional/FactoryMaker.java b/src/practice/creational/notional/FactoryMaker.java new file mode 100644 index 0000000..a2ac54d --- /dev/null +++ b/src/practice/creational/notional/FactoryMaker.java @@ -0,0 +1,21 @@ +package practice.creational.notional; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.ToString; +import lombok.experimental.UtilityClass; +import lombok.extern.java.Log; +import practice.creational.factory.CoinFactory; + +@Log +@ToString +@UtilityClass +@EqualsAndHashCode +public final class FactoryMaker { + + public static CoinFactory makeMint(@NonNull final FactoryType factoryType) { + final CoinFactory coinFactory = factoryType.getCreator().get(); // Creation + log.info("CATEGORY of Coin Minting FACTORY => [" + coinFactory + "]"); + return coinFactory; // Return the SPECIFIC category of COIN minting FACTORY + } +} diff --git a/src/practice/creational/notional/FactoryType.java b/src/practice/creational/notional/FactoryType.java new file mode 100644 index 0000000..8a7d479 --- /dev/null +++ b/src/practice/creational/notional/FactoryType.java @@ -0,0 +1,20 @@ +package practice.creational.notional; + +import java.util.function.Supplier; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import practice.creational.factory.CoinFactory; +import practice.creational.factory.MassFactory; +import practice.creational.factory.RareFactory; + +@Getter +@RequiredArgsConstructor +public enum FactoryType { + + MASS(MassFactory::new), // Holds CONSTRUCTOR + RARE(RareFactory::new); // Holds CONSTRUCTOR + + @NonNull + private final Supplier creator; +} From bfeecf8930e7dfa68101a4de53f78f033672c059 Mon Sep 17 00:00:00 2001 From: Subhatav Dhali Date: Sat, 2 Nov 2024 20:33:25 +0530 Subject: [PATCH 3/6] Implement the Builder Design Pattern --- .../creational/builder/BuilderDemo.java | 21 +++++++++ .../creational/builder/CustomPizza.java | 47 +++++++++++++++++++ .../creational/builder/PizzaElement.java | 24 ++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/practice/creational/builder/BuilderDemo.java create mode 100644 src/practice/creational/builder/CustomPizza.java create mode 100644 src/practice/creational/builder/PizzaElement.java diff --git a/src/practice/creational/builder/BuilderDemo.java b/src/practice/creational/builder/BuilderDemo.java new file mode 100644 index 0000000..6782ee1 --- /dev/null +++ b/src/practice/creational/builder/BuilderDemo.java @@ -0,0 +1,21 @@ +package practice.creational.builder; + +import practice.creational.builder.CustomPizza.PizzaChef; +import practice.creational.builder.PizzaElement.DoughType; +import practice.creational.builder.PizzaElement.SauceType; +import practice.creational.builder.PizzaElement.ToppingType; + +/** + * Example of Builder Design Pattern + */ +public final class BuilderDemo { + + public static void main(final String... arguments) { + + new PizzaChef(DoughType.BAKED).setSauceType(SauceType.HOT) + .setTopping(ToppingType.CAPSICUM_MUSHROOM).cookPizza().eatPizza(); + + new PizzaChef(DoughType.CROSS).setSauceType(SauceType.MILD) + .setTopping(ToppingType.CHEESE_CORN_TOMATO).cookPizza().eatPizza(); + } +} diff --git a/src/practice/creational/builder/CustomPizza.java b/src/practice/creational/builder/CustomPizza.java new file mode 100644 index 0000000..8524a53 --- /dev/null +++ b/src/practice/creational/builder/CustomPizza.java @@ -0,0 +1,47 @@ +package practice.creational.builder; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.Accessors; +import lombok.extern.java.Log; + +@Log +@ToString +@EqualsAndHashCode +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public final class CustomPizza { + + @NonNull + private final PizzaElement.DoughType doughType; + @NonNull + private final PizzaElement.SauceType sauceType; + @NonNull + private final PizzaElement.ToppingType topping; + + public void eatPizza() { + log.info("EATING Pizza => " + this); + } + + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor + @Accessors(chain = true) + protected static final class PizzaChef { + + @NonNull + private final PizzaElement.DoughType doughType; + + private PizzaElement.SauceType sauceType; + private PizzaElement.ToppingType topping; + + public CustomPizza cookPizza() { + log.info("COOKING Pizza => " + this); // In OVEN + return new CustomPizza(doughType, sauceType, topping); + } + } +} diff --git a/src/practice/creational/builder/PizzaElement.java b/src/practice/creational/builder/PizzaElement.java new file mode 100644 index 0000000..7ba13b0 --- /dev/null +++ b/src/practice/creational/builder/PizzaElement.java @@ -0,0 +1,24 @@ +package practice.creational.builder; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ToString +@EqualsAndHashCode +public final class PizzaElement { + + protected enum DoughType { + + BAKED, CROSS + } + + protected enum SauceType { + + HOT, MILD + } + + protected enum ToppingType { + + CAPSICUM_MUSHROOM, CHEESE_CORN_TOMATO + } +} From 8585c5c8c163afcdd9d113b50e5a1aebf726002a Mon Sep 17 00:00:00 2001 From: Subhatav Dhali Date: Sat, 2 Nov 2024 20:34:23 +0530 Subject: [PATCH 4/6] Implement the Object Pool Design Pattern --- src/practice/creational/pool/Candidate.java | 31 ++++++++++++++ src/practice/creational/pool/ObjectPool.java | 43 ++++++++++++++++++++ src/practice/creational/pool/PersonPool.java | 14 +++++++ src/practice/creational/pool/PoolDemo.java | 37 +++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 src/practice/creational/pool/Candidate.java create mode 100644 src/practice/creational/pool/ObjectPool.java create mode 100644 src/practice/creational/pool/PersonPool.java create mode 100644 src/practice/creational/pool/PoolDemo.java diff --git a/src/practice/creational/pool/Candidate.java b/src/practice/creational/pool/Candidate.java new file mode 100644 index 0000000..69f8e0a --- /dev/null +++ b/src/practice/creational/pool/Candidate.java @@ -0,0 +1,31 @@ +package practice.creational.pool; + +import java.util.concurrent.atomic.AtomicInteger; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.ToString; +import lombok.extern.java.Log; + +@Log +@ToString +@EqualsAndHashCode +public final class Candidate { + + private static final AtomicInteger counter = new AtomicInteger(0); + + @NonNull + private final int id; + + public Candidate() { + id = counter.incrementAndGet(); + try { + Thread.sleep(100L); // TIME to BIRTH + } catch (final InterruptedException exception) { + log.warning(exception.getLocalizedMessage()); + } + } + + public void print() { + log.info("INSTANCE from Pool => [" + this + "]"); + } +} diff --git a/src/practice/creational/pool/ObjectPool.java b/src/practice/creational/pool/ObjectPool.java new file mode 100644 index 0000000..79c9b60 --- /dev/null +++ b/src/practice/creational/pool/ObjectPool.java @@ -0,0 +1,43 @@ +package practice.creational.pool; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.ToString; +import lombok.extern.java.Log; + +@Log +@ToString +@EqualsAndHashCode +public abstract sealed class ObjectPool permits PersonPool { + + private final LinkedHashSet free = new LinkedHashSet<>(); + private final HashSet beingUsed = new HashSet<>(); + + protected abstract T create(); + + public synchronized T borrow() { + if (free.isEmpty()) { // CHECKS availability inside `Available` pool + log.info("Creating FRESHLY since `Available` pool is empty!"); + free.addLast(create()); // ADDS fresh at END into `Available` pool + } + log.info("Lending SINGLE from `Available` into `Occupied` pool..."); + final var instance = free.removeFirst(); // TAKES from `Occupied` pool + beingUsed.add(instance); // REGISTERS `instance` into `Available` pool + return instance; // LENDS `instance` object to be CONSUMED by any USER + } + + public synchronized void remit(@NonNull final T instance) { + log.info("Restoring BACK into `Available` from `Occupied` pool..."); + beingUsed.remove(instance); // DETACHES `instance` from `Occupied` pool + free.addLast(instance); // ADDS `instance` at END into `Available` pool + } + + public synchronized void status() { + final String nbAvailableItems = "nbAvailableItems=" + free.size(); + final String nbOccupiedItems = "nbOccupiedItems=" + beingUsed.size(); + final var nbTotalItems = "[" + nbAvailableItems + ", " + nbOccupiedItems + "]"; + log.info("Pool STATUS => " + nbTotalItems); // Prints CURRENT pool STATUS + } +} diff --git a/src/practice/creational/pool/PersonPool.java b/src/practice/creational/pool/PersonPool.java new file mode 100644 index 0000000..7eb4bf7 --- /dev/null +++ b/src/practice/creational/pool/PersonPool.java @@ -0,0 +1,14 @@ +package practice.creational.pool; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public final class PersonPool extends ObjectPool { + + @Override + protected Candidate create() { + return new Candidate(); + } +} diff --git a/src/practice/creational/pool/PoolDemo.java b/src/practice/creational/pool/PoolDemo.java new file mode 100644 index 0000000..a0e6f9f --- /dev/null +++ b/src/practice/creational/pool/PoolDemo.java @@ -0,0 +1,37 @@ +package practice.creational.pool; + +/** + * Example of Object Pool Design Pattern + */ +public final class PoolDemo { + + public static void main(final String[] arguments) { + + final var objectPool = new PersonPool(); + objectPool.status(); // INITIAL status + + final var personObj1 = objectPool.borrow(); + personObj1.print(); // FIRST instance + + objectPool.status(); // CURRENT status + + final var personObj2 = objectPool.borrow(); + personObj2.print(); // SECOND instance + + objectPool.status(); // CURRENT status + + objectPool.remit(personObj1); // REMIT + objectPool.status(); // CURRENT status + + objectPool.remit(personObj2); // REMIT + objectPool.status(); // CURRENT status + + final var personObj3 = objectPool.borrow(); + personObj3.print(); // Not THIRD instance + + objectPool.status(); // CURRENT status + + objectPool.remit(personObj3); // REMIT + objectPool.status(); // CURRENT status + } +} From 1334e8ca8142137f8eb8e51ecbfeadf3aa7ca61c Mon Sep 17 00:00:00 2001 From: Subhatav Dhali Date: Sat, 2 Nov 2024 20:34:56 +0530 Subject: [PATCH 5/6] Implement the Prototype Design Pattern --- src/practice/creational/prototype/Knife.java | 21 ++++++++++++++++++ .../creational/prototype/Prototype.java | 12 ++++++++++ .../creational/prototype/PrototypeDemo.java | 22 +++++++++++++++++++ src/practice/creational/prototype/Rifle.java | 21 ++++++++++++++++++ src/practice/creational/prototype/Weapon.java | 11 ++++++++++ 5 files changed, 87 insertions(+) create mode 100644 src/practice/creational/prototype/Knife.java create mode 100644 src/practice/creational/prototype/Prototype.java create mode 100644 src/practice/creational/prototype/PrototypeDemo.java create mode 100644 src/practice/creational/prototype/Rifle.java create mode 100644 src/practice/creational/prototype/Weapon.java diff --git a/src/practice/creational/prototype/Knife.java b/src/practice/creational/prototype/Knife.java new file mode 100644 index 0000000..32aa9e6 --- /dev/null +++ b/src/practice/creational/prototype/Knife.java @@ -0,0 +1,21 @@ +package practice.creational.prototype; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.java.Log; + +@Log +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = false) +public final class Knife extends Weapon { + + @NonNull + private final String name; + + @Override + public void printWeaponDescription() { + final var className = this.getClass().getSimpleName(); // CURRENT Weapon NAME + log.info("Object of <" + name + "> " + className + " => [" + this + "]"); + } +} diff --git a/src/practice/creational/prototype/Prototype.java b/src/practice/creational/prototype/Prototype.java new file mode 100644 index 0000000..c9dfdef --- /dev/null +++ b/src/practice/creational/prototype/Prototype.java @@ -0,0 +1,12 @@ +package practice.creational.prototype; + +import lombok.SneakyThrows; + +public abstract sealed class Prototype implements Cloneable permits Weapon { + + @SneakyThrows + @SuppressWarnings("unchecked") + public T copy() { + return (T) super.clone(); // Does SHALLOW copy using `Object.clone()` method + } +} diff --git a/src/practice/creational/prototype/PrototypeDemo.java b/src/practice/creational/prototype/PrototypeDemo.java new file mode 100644 index 0000000..768e1db --- /dev/null +++ b/src/practice/creational/prototype/PrototypeDemo.java @@ -0,0 +1,22 @@ +package practice.creational.prototype; + +/** + * Example of Prototype Design Pattern + */ +public final class PrototypeDemo { + + public static void main(final String[] arguments) { + + final var knifeWeapon1 = new Knife("butterfly"); + final var rifleWeapon1 = new Rifle("dragunov"); + + knifeWeapon1.printWeaponDescription(); // Location of `object` + rifleWeapon1.printWeaponDescription(); // Location of `object` + + final var knifeWeapon2 = knifeWeapon1.copy(); // Cloned `object` + final var rifleWeapon2 = rifleWeapon1.copy(); // Cloned `object` + + knifeWeapon2.printWeaponDescription(); // Location of `object` + rifleWeapon2.printWeaponDescription(); // Location of `object` + } +} diff --git a/src/practice/creational/prototype/Rifle.java b/src/practice/creational/prototype/Rifle.java new file mode 100644 index 0000000..bdd8603 --- /dev/null +++ b/src/practice/creational/prototype/Rifle.java @@ -0,0 +1,21 @@ +package practice.creational.prototype; + +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.java.Log; + +@Log +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = false) +public final class Rifle extends Weapon { + + @NonNull + private final String name; + + @Override + public void printWeaponDescription() { + final var className = this.getClass().getSimpleName(); // CURRENT Weapon NAME + log.info("Object of <" + name + "> " + className + " => [" + this + "]"); + } +} diff --git a/src/practice/creational/prototype/Weapon.java b/src/practice/creational/prototype/Weapon.java new file mode 100644 index 0000000..7cb0cc2 --- /dev/null +++ b/src/practice/creational/prototype/Weapon.java @@ -0,0 +1,11 @@ +package practice.creational.prototype; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +public abstract sealed class Weapon extends Prototype permits Knife, Rifle { + + public abstract void printWeaponDescription(); // Make DIFFERENT types of WEAPONS +} From 6e1ce64beb0cd22d72a630be08ccdb485dc96980 Mon Sep 17 00:00:00 2001 From: Subhatav Dhali Date: Sat, 2 Nov 2024 20:35:25 +0530 Subject: [PATCH 6/6] Implement the Singleton Design Pattern --- .../creational/singleton/BillPughHolder.java | 27 ++++++++++++++++ .../creational/singleton/DoubleCheckLock.java | 30 ++++++++++++++++++ .../creational/singleton/EagerLoaded.java | 22 +++++++++++++ .../creational/singleton/EnumSingleton.java | 18 +++++++++++ .../creational/singleton/LazyLoaded.java | 25 +++++++++++++++ .../creational/singleton/SingletonDemo.java | 31 +++++++++++++++++++ .../creational/singleton/StaticBlock.java | 26 ++++++++++++++++ .../creational/singleton/ThreadSafeLazy.java | 26 ++++++++++++++++ 8 files changed, 205 insertions(+) create mode 100644 src/practice/creational/singleton/BillPughHolder.java create mode 100644 src/practice/creational/singleton/DoubleCheckLock.java create mode 100644 src/practice/creational/singleton/EagerLoaded.java create mode 100644 src/practice/creational/singleton/EnumSingleton.java create mode 100644 src/practice/creational/singleton/LazyLoaded.java create mode 100644 src/practice/creational/singleton/SingletonDemo.java create mode 100644 src/practice/creational/singleton/StaticBlock.java create mode 100644 src/practice/creational/singleton/ThreadSafeLazy.java diff --git a/src/practice/creational/singleton/BillPughHolder.java b/src/practice/creational/singleton/BillPughHolder.java new file mode 100644 index 0000000..ced2c69 --- /dev/null +++ b/src/practice/creational/singleton/BillPughHolder.java @@ -0,0 +1,27 @@ +package practice.creational.singleton; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.UtilityClass; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class BillPughHolder { + + @UtilityClass + private static final class InstanceHolder { + + private static final BillPughHolder INSTANCE = new BillPughHolder(); + } + + public static BillPughHolder getInstance() { + return InstanceHolder.INSTANCE; + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +} diff --git a/src/practice/creational/singleton/DoubleCheckLock.java b/src/practice/creational/singleton/DoubleCheckLock.java new file mode 100644 index 0000000..71aef89 --- /dev/null +++ b/src/practice/creational/singleton/DoubleCheckLock.java @@ -0,0 +1,30 @@ +package practice.creational.singleton; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class DoubleCheckLock { + + // `volatile` => ATOMIC Access by RACING Threads + private static volatile DoubleCheckLock instance; + + public static DoubleCheckLock getInstance() { + if (instance == null) { + synchronized (DoubleCheckLock.class) { + if (instance == null) { + instance = new DoubleCheckLock(); + } + } + } + return instance; // Return SAME Object + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +} diff --git a/src/practice/creational/singleton/EagerLoaded.java b/src/practice/creational/singleton/EagerLoaded.java new file mode 100644 index 0000000..4389686 --- /dev/null +++ b/src/practice/creational/singleton/EagerLoaded.java @@ -0,0 +1,22 @@ +package practice.creational.singleton; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class EagerLoaded { + + private static final EagerLoaded INSTANCE = new EagerLoaded(); + + public static EagerLoaded getInstance() { + return INSTANCE; + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +} diff --git a/src/practice/creational/singleton/EnumSingleton.java b/src/practice/creational/singleton/EnumSingleton.java new file mode 100644 index 0000000..6fbae7f --- /dev/null +++ b/src/practice/creational/singleton/EnumSingleton.java @@ -0,0 +1,18 @@ +package practice.creational.singleton; + +import lombok.extern.java.Log; + +@Log +public enum EnumSingleton { + + INSTANCE; + + @Override + public String toString() { + return getDeclaringClass().getCanonicalName() + "@" + hashCode(); + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +} diff --git a/src/practice/creational/singleton/LazyLoaded.java b/src/practice/creational/singleton/LazyLoaded.java new file mode 100644 index 0000000..24e9cf9 --- /dev/null +++ b/src/practice/creational/singleton/LazyLoaded.java @@ -0,0 +1,25 @@ +package practice.creational.singleton; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class LazyLoaded { + + private static LazyLoaded instance; + + public static LazyLoaded getInstance() { + if (instance == null) { + instance = new LazyLoaded(); + } + return instance; // Return SAME Object + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +} diff --git a/src/practice/creational/singleton/SingletonDemo.java b/src/practice/creational/singleton/SingletonDemo.java new file mode 100644 index 0000000..2a4383c --- /dev/null +++ b/src/practice/creational/singleton/SingletonDemo.java @@ -0,0 +1,31 @@ +package practice.creational.singleton; + +/** + * Example of Singleton Design Pattern + */ +public final class SingletonDemo { + + public static void main(final String... arguments) { + + EagerLoaded.getInstance().printInstanceDetails(); + EagerLoaded.getInstance().printInstanceDetails(); + + StaticBlock.getInstance().printInstanceDetails(); + StaticBlock.getInstance().printInstanceDetails(); + + LazyLoaded.getInstance().printInstanceDetails(); + LazyLoaded.getInstance().printInstanceDetails(); + + ThreadSafeLazy.getInstance().printInstanceDetails(); + ThreadSafeLazy.getInstance().printInstanceDetails(); + + DoubleCheckLock.getInstance().printInstanceDetails(); + DoubleCheckLock.getInstance().printInstanceDetails(); + + BillPughHolder.getInstance().printInstanceDetails(); + BillPughHolder.getInstance().printInstanceDetails(); + + EnumSingleton.INSTANCE.printInstanceDetails(); + EnumSingleton.INSTANCE.printInstanceDetails(); + } +} diff --git a/src/practice/creational/singleton/StaticBlock.java b/src/practice/creational/singleton/StaticBlock.java new file mode 100644 index 0000000..3232861 --- /dev/null +++ b/src/practice/creational/singleton/StaticBlock.java @@ -0,0 +1,26 @@ +package practice.creational.singleton; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class StaticBlock { + + private static final StaticBlock INSTANCE; + + static { + INSTANCE = new StaticBlock(); // Initialized EAGERLY + } + + public static StaticBlock getInstance() { + return INSTANCE; + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +} diff --git a/src/practice/creational/singleton/ThreadSafeLazy.java b/src/practice/creational/singleton/ThreadSafeLazy.java new file mode 100644 index 0000000..70a3cd9 --- /dev/null +++ b/src/practice/creational/singleton/ThreadSafeLazy.java @@ -0,0 +1,26 @@ +package practice.creational.singleton; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.java.Log; + +@Log +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ThreadSafeLazy { + + // `volatile` => ATOMIC Access by RACING Threads + private static volatile ThreadSafeLazy instance; + + public static synchronized ThreadSafeLazy getInstance() { + if (instance == null) { + instance = new ThreadSafeLazy(); + } + return instance; // Return SAME Object + } + + public void printInstanceDetails() { + log.info("Object => [" + this + "]"); + } +}