0% found this document useful (0 votes)
7 views

Mastering Design Patterns in Java _ by Dharshi Balasubramaniyam _ Javarevisited _ Feb, 2024 _ Medium

Uploaded by

hueprophuhai
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Mastering Design Patterns in Java _ by Dharshi Balasubramaniyam _ Javarevisited _ Feb, 2024 _ Medium

Uploaded by

hueprophuhai
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Mastering Design Patterns in Java


Dharshi Balasubramaniyam · Follow
Published in Javarevisited · 16 min read · Feb 26, 2024

268 6

Figure 1: Design patterns

In the world of software engineering, turning ideas into actual code can be
tricky.
00 : 00 : 4 1

Get Premium

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 1/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

As developers, our goal is not just to make things


work, but also to make sure our code is maintainable,
scalable, adaptable and reusable.

Enter design patterns — the time-tested blueprints that empower us to tackle


recurring design problems with elegance and efficiency.

At its heart, a design pattern is like a ready-made solution for common


problems we face when designing software. These solutions are like
shortcuts, saving us time and effort by using proven strategies that experts
have refined over many years.

In this article, we’ll delve into some of the most important design patterns
that every developer should be familiar with. We’ll explore their principles,
why they’re useful, and how you can use them in real projects. Whether
you’re struggling with creating objects, organizing relationships between
classes, or managing how objects behave, there’s a design pattern that can
help.

Let’s begin.

1. Singleton pattern
The Singleton pattern is a creational design pattern that ensures a class has
only one instance and provides a global point of access to that instance. In
simpler terms, it’s like ensuring there’s only one unique copy of a particular

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 2/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

object in your program, and you can access that object from anywhere in
your code.

Figure 2: Singleton design pattern

Let’s take a simple real-world example: the clipboard. Picture multiple


applications or processes running on a computer, each attempting to access
the clipboard concurrently. If each application were to create its own version
of the clipboard to manage copy and paste operations, it could lead to
conflicting data.

public class Clipboard {

private String value;

public void copy(String value) {


this.value = value;
}

public String paste() {


return value;
}
}

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 3/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

In the above example, we've defined a Clipboard class capable of copying


and pasting values. However, if we were to create multiple instances of
Clipboard , each instance would hold its own separate data.

Open in app Sign up Sign in

public class Main {


Search
public static void main(String[] args) { Write

Clipboard clipboard1 = new Clipboard();


Clipboard clipboard2 = new Clipboard();

clipboard1.copy("Java");
clipboard2.copy("Design patterns");

System.out.println(clipboard1.paste()); // output: Java


System.out.println(clipboard2.paste()); // output: Design patterns
}
}

Clearly, this isn’t ideal. We expect both clipboard instances to display the
same value. This is precisely where the Singleton pattern proves its worth.

public class Clipboard {

private String value;

private static Clipboard clipboard = null;

// Private constructor to prevent instantiation from outside


private Clipboard() {}

// Method to provide access to the singleton instance


public static Clipboard getInstance() {
if (clipboard == null) {
clipboard = new Clipboard();
}
return clipboard;
}

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 4/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

public void copy(String value) {


this.value = value;
}

public String paste() {


return value;
}
}

By implementing the Singleton pattern, we ensure that only one instance of


the Clipboard class exists throughout the program execution.

public class Main {


public static void main(String[] args) {

// Getting the singleton instances


Clipboard clipboard1 = Clipboard.getInstance();
Clipboard clipboard2 = Clipboard.getInstance();

clipboard1.copy("Java");
clipboard2.copy("Design patterns");

System.out.println(clipboard1.paste()); // output: Design patterns


System.out.println(clipboard2.paste()); // output: Design patterns
}
}

Now, both clipboard1 and clipboard2 reference the same instance of the
Clipboard class, ensuring consistency across the application.

2. Factory Design pattern

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 5/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

The Factory Design Pattern is a creational design pattern that provides an


interface for creating objects in a super class but allows subclasses to decide
which class to instantiate. In other words, it provides a way to delegate the
instantiation logic to child classes.

Figure 3: Factory design pattern

Imagine you’re building a program that simulates a simple console based


calculator. You have different types of operations like addition, subtraction,
multiplication, division etc. Each operation has its own unique behavior.
Now, you want to create these operation objects in your program based on
customer choice.

The challenge is you need a way to create these operation objects without
making your code too complex or tightly coupled. This means you don’t want
your code to rely too heavily on the specific classes of operations directly.
You also want to make it easy to add new types of operations later without
changing a lot of code.

The Factory Design Pattern helps you solve this problem by providing a way
to create objects without specifying their exact class. Instead, you delegate
the creation process to a factory class.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 6/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

1. Define the product interface. ( Operation ).

public interface Operation {


double calculate(double number1, double number2);
}

2. Implement concrete products for each operation.

// for addition
public class AddOperation implements Operation{
@Override
public double calculate(double number1, double number2) {
return number1 + number2;
}
}

// for substration
public class SubOperation implements Operation{
@Override
public double calculate(double number1, double number2) {
return number1 - number2;
}
}

// for multiplication
public class MulOperation implements Operation{
@Override
public double calculate(double number1, double number2) {
return number1 * number2;
}
}

// for division
public class DivOperation implements Operation{
@Override
public double calculate(double number1, double number2) {
if(number2 == 0)
throw new ArithmeticException("Cannot divide by zero!");
return number1 / number2;
}
https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 7/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

// An exception class invokes when user input invalid choice for operation
public class InvalidOperationException extends Exception{
public InvalidOperationException(String message) {
super(message);
}

3. Create a factory class ( OperationFactory ) with a method ( getInstance ) to


create objects based on some parameter.

public interface OperationFactory {


Operation getInstance(int choice) throws InvalidOperation;
}

public class OperationFactoryImpl implements OperationFactory{


@Override
public Operation getInstance(int choice) throws InvalidOperationException {
if(choice==1)
return new AddOperation();
else if(choice==2)
return new SubOperation();
else if(choice==3)
return new MulOperation();
else if(choice==4)
return new DivOperation();
throw new InvalidOperation("Invalid operation selected!");
}
}

4. Use the factory to create objects without knowing their specific classes.

public static void main(String[] args) {


Scanner scan = new Scanner(System.in);
https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 8/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Output output = new ConsoleOutput();

try {

System.out.println("\n1. Addition(+)\n2. Subtraction(-)\n3. Multiplication(*)

// getting choice from user


System.out.println("\n\nSelect your operation (1-4): ");
int choice = scan.nextInt()

// getting 2 operands from user


System.out.println("Enter first operand: ");
double operand1 = scan.nextDouble();
System.out.println("Enter second operand: ");
double operand2 = scan.nextDouble();

// create opeartion instance based on user choice


OperationFactory operationFactory = new OperationFactoryImpl();
Operation operation = operationFactory.getInstance(choice);

// printing result
System.out.println("\nThis result is " + operation.calculate(operand1, operan
}
catch (InputMismatchException e) {
System.out.println("Invalid input type!\n");
}
catch (InvalidOperation | ArithmeticException e) {
System.out.println(e.getMessage());
}

scan.close();
}

Here the Main class demonstrates the usage of the factory to create different
operation objects without knowing their specific implementation classes
(Loose coupling). It only interacts with the factory interface. Not only that,
but we can also easily add new types of operations without changing existing
client code. We are just needed to create a new concrete product and update
the factory if necessary.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 9/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

3. Builder pattern
the Builder Pattern provides a way to construct an object by allowing you to
set its various properties (or attributes) in a step-by-step manner.

Some of the parameters might be optional for an object, but we are forced to
send all the parameters and optional parameters need to send as NULL. We
can solve this issue with large number of parameters by providing a
constructor with required parameters and then different setter methods to
set the optional parameters.

This pattern is particularly useful when dealing with objects that have many
optional parameters or configurations.

Imagine we’re developing a user entity. Users have different properties like
name, email, phone and city etc. Here name and email are required fields
and phone and city are optional. Now, each person might have different
combinations of these properties. Some might have city, others might not.
Some might have phone, others might not. The Builder Design Pattern helps
you create these users flexibly, step by step.

// Main product class


public class User {
private String name; // required field
private String email; // required field
private String phone; // optional field
private String city; // optional field

public User(UserBuilder userBuilder) {


this.name = userBuilder.getName();
this.email = userBuilder.getEmail();
this.phone = userBuilder.getPhone();
this.city = userBuilder.getCity();

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 10/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

public static UserBuilder builder(String name, String email) {


return new UserBuilder(name, email);
}

@Override
public String toString() {
return "User = " +
"{ name: '" + name + '\'' +
", email: '" + email + '\'' +
", phone: '" + phone + '\'' +
", city: '" + city + '\'' +
" }";
}

// builder class
public static class UserBuilder {
private String name; // required field
private String email; // required field
private String phone = "unknown"; // optional field
private String city = "unknown"; // optional field

public UserBuilder(String name, String email) {


this.name = name;
this.email = email;
}

// getters

public UserBuilder name(String name) {


this.name = name;
return this;
}

public UserBuilder email(String email) {


this.email = email;
return this;
}

public UserBuilder phone(String phone) {


this.phone = phone;
return this;
}

public UserBuilder city(String city) {


this.city = city;
return this;
}

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 11/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

public User build() {


return new User(this);
}
}

UserBuilder class: Is the inner builder class responsible for constructing


User objects. It has fields representing the presence or absence of
different properties ( name , email , phone , city ). The class provides setter
methods for each properties, which return the builder itself ( name() ,
phone() , city() , email() This enables method chaining.

User class: Is the class represents the product you want to build using the
builder pattern. It has private fields to represent the properties of the
user ( name , email , phone , city ). The constructor of User takes a
UserBuilder object and initializes its fields based on the builder's settings.
There is a static method builder() that returns a new instance of
UserBuilder , providing a convenient way to create a new builder.

Here’s an example of how you can use this code to create a user with
optional properties:

public class Main {


public static void main(String[] args) {

User user1 = User


.builder("John", "john@[email protected]")
.build();

System.out.println(user1); // User = { name: 'John', email: 'john@abc@gm

User user2 = User


.builder("Mary", "mary@[email protected]")
.city("Colombo")

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 12/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

.build();

System.out.println(user2); // User = { name: 'Mary', email: 'mary@abc@gm


}

So that’s what builder patterns is guys. This pattern is useful when you have
complex objects with many optional parameters, and it helps keep your code
clean and easy to understand. It allows you to construct different variations
of objects with the same builder, adjusting parameters as needed.

4. Adapter pattern
The Adapter pattern is a structural design pattern that allows objects with
incompatible interfaces to work together. It acts as a bridge between two
incompatible interfaces.

Imagine a situation where two classes or components perform similar tasks


but have different method names, parameter types, or structures. The
Adapter pattern allows these incompatible interfaces to work together by
providing a wrapper (the adapter) that translates the interface of one class
into an interface that the client expects.

Target is the interface expected by the client.

Adaptee is the class that needs to be adapted.

Adapter is the class that implements the Target interface and wraps the
Adaptee class.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 13/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Client class is the class that uses the adapter to interact with the Adaptee
through the Tareget interface.

Figure 4: Adaptor design pattern

// Target interface
interface CellPhone {
void call();
}

// Adaptee (the class to be adapted)


class FriendCellPhone {
public void ring() {
System.out.println("Ringing");
}
}

// Adapter class implementing the Target interface


class CellPhoneAdapter implements CellPhone {
private FriendCellPhone friendCellPhone;

public CellPhoneAdapter(FriendCellPhone friendCellPhone) {


this.friendCellPhone = friendCellPhone;
}

@Override
public void call() {
friendCellPhone.ring();
}
}

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 14/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

// Client class
public class AdapterMain {
public static void main(String[] args) {
// Using the adapter to make Adaptee work with Target interface
FriendCellPhone adaptee = new FriendCellPhone();
CellPhone adapter = new CellPhoneAdapter(adaptee);
adapter.call();
}
}

In this example:

CellPhone is the target interface that your client code expects, and you do
not have an implementation of it.

FriendCellPhone is the class you want to adapt/reuse (the Adaptee), which


has a method named ring rather than creating new implementaion of
CellPhone interface.

CellPhoneAdapter is the adapter class that implements the CellPhone

interface and wraps an instance of FriendCellPhone . The call method in


the adapter delegates the call to the ring method of the FriendCellPhone

class.

AdapterMain class serves as the client that demonstrates the usage of the
Adapter pattern in action.

Why adapter pattern?

The Adaptee might be a class from a third-party library or a legacy


codebase that you can’t modify directly. By using an adapter, you can
adapt its interface to match the interface expected by the client without
modifying the original code.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 15/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

The client might only require specific functionality from the Adaptee. By
using an adapter, you can provide a tailored interface that exposes only
the necessary functionality, rather than exposing the entire interface of
the Adaptee.

It might seem that you can achieve similar functionality by creating an


instance of the Target interface directly, using an adapter provides
benefits in terms of code reusability, maintainability, and flexibility,
especially when dealing with existing code or third-party libraries.

5. Decorator pattern
The Decorator Pattern is a design pattern in object-oriented programming
that allows behavior to be added to individual objects, either statically or
dynamically, without affecting the behavior of other objects from the same
class.

In this pattern, there is a base class (or interface) that defines the common
functionality, and one or more decorator classes that add additional
behavior. These decorator classes wrap the original object, augmenting its
behavior in a modular and flexible way.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 16/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Figure 5: Decorator design pattern

Imagine, you are tasked with creating a drawing application that allows users
to create and customize shapes with various decorations. It should be able to
easily add new decorators for additional features without changing the
existing code for shapes or other decorators.

Let’s see how we can achieve that using decorator pattern.

// Shape Interface
interface Shape {
void draw();
String getName();
}
https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 17/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

// Concrete Shape: Circle


class Circle implements Shape {
private String name;

public Circle(String name) {


this.name = name;
}

public String getName() {


return name;
}

@Override
public void draw() {
System.out.println("Drawing circle, " + getName() + ".");
}
}

Shape Interface: Defines the basic operations that all shapes should
support. In this case, it includes the draw() method to draw the shape
and getName() to get the name of the shape.

Circle Class: Implements the Shape interface, representing a concrete


shape (in this case, a circle). It has a name attribute and implements the
draw() method to draw a circle.

// Abstract Decorator Class


abstract class ShapeDecorator implements Shape {
private Shape decoratedShape;

public ShapeDecorator(Shape decoratedShape) {


this.decoratedShape = decoratedShape;
}

@Override
public void draw() {
decoratedShape.draw();
}

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 18/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

@Override
public String getName() {
return decoratedShape.getName();
}
}

ShapeDecorator Abstract Class: An abstract class implementing the


Shape interface. It contains a reference to a Shape object (the decorated
shape) and delegates the draw() method to this object.

// Concrete Decorator: BorderDecorator


class BorderDecorator extends ShapeDecorator {
private String color;
private int widthInPxs;

public BorderDecorator(Shape decoratedShape, String color, int widthInPxs) {


super(decoratedShape);
this.color = color;
this.widthInPxs = widthInPxs;
}

@Override
public void draw() {
super.draw();
System.out.println("Adding " + widthInPxs + "px, " + color + " color bor
}
}

// Concrete Decorator: ColorDecorator


class ColorDecorator extends ShapeDecorator {
private String color;

public ColorDecorator(Shape decoratedShape, String color) {


super(decoratedShape);
this.color = color;
}

@Override
public void draw() {
super.draw();
System.out.println("Filling with " + color + " color to " + getName() +

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 19/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

}
}

BorderDecorator and ColorDecorator Classes: Concrete decorator classes


that extend ShapeDecorator . They add additional features to the decorated
shapes, such as borders and colors. They override the draw() method to
add their specific functionality while also calling the draw() method of
the decorated shape.

// Main Class
public class DecoratorMain {
public static void main(String[] args) {
// Create a circle
Shape circle1 = new Circle("circle1");

// Decorate the circle with a border


Shape circle1WithBorder = new BorderDecorator(circle1, "red", 2);

// Decorate the circle with a color


Shape circle1WithBorderAndColor = new ColorDecorator(circle1WithBorder,

// Draw the decorated circle


circle1WithBorderAndColor.draw();

// output
// Drawing circle, circle1.
// Adding 2px, red color border to circle1.
// Filling with blue color to circle1.
}
}

DecoratorMain Class: Contains the main() method where the decorator


pattern is demonstrated. It creates a circle, decorates it with a border,

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 20/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

and then further decorates it with a color. Finally, it calls the draw()

method to visualize the decorated shape.

Now, with the implementation of the Decorator Pattern, our drawing


application gains the remarkable ability to embellish not only circles but also
a plethora of geometric shapes such as rectangles, triangles, and beyond.
Moreover, the extensibility of this pattern enables us to seamlessly integrate
additional decorators, offering features like transparency, diverse border
styles (solid, dotted), and much more. This dynamic enhancement capability,
achieved without altering the core structure of the shapes, underscores the
pattern’s prowess in promoting code reusability, flexibility, and scalability.

6. Observer pattern
The Observer Pattern a behavioral design pattern commonly used in object-
oriented programming to establish a one-to-many dependency between
objects. In this pattern, one object (called the subject or observable)
maintains a list of its dependents (observers) and notifies them of any state
changes, usually by calling one of their methods.

Here’s how it works:

Subject: This is the object that holds the state and manages the list of
observers. It provides methods to attach, detach, and notify observers.

Observer: This is the interface that defines the method(s) that the subject
calls to notify the observer of any state changes. Typically, observers
implement this interface.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 21/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Concrete Subject: This is the concrete implementation of the subject


interface. It maintains the state and sends notifications to observers
when the state changes.

Concrete Observer: This is the concrete implementation of the observer


interface. It registers itself with a subject to receive notifications and
implements the update method to respond to state changes.

Figure 6: Observer design pattern

In the context of a YouTube channel subscriber scenario, the YouTube


channel is the subject, and the subscribers are the observers. When an event
happens in a YouTube channel, it notifies all its subscribers about the new
video so they can watch it.

Let’s implement this example in code,

public enum EventType {


NEW_VIDEO,
LIVE_STREAM
}

public class YoutubeEvent {


private EventType eventType;
private String topic;

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 22/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

public YoutubeEvent(EventType eventType, String topic) {


this.eventType = eventType;
this.topic = topic;
}

// getters ans setters

@Override
public String toString() {
return eventType.name() + " on " + topic;
}
}

EventType: The EventType enum defines the types of events that can
occur, such as NEW_VIDEO , LIVE_STREAM and more.

Event: The YoutubeEvent class represents the events that occur in the
system. It contains information such as the type of event and the topic.

public interface Subject {

void addSubscriber(Observer observer);


void removeSubscriber(Observer observer);
void notifyAllSubscribers(YoutubeEvent event);

public interface Observer {


void notifyMe(String youtubeChannelName, YoutubeEvent event);
}

Subject: The Subject interface declares methods to manage subscribers


( addSubscriber and removeSubscriber ) and to notify them
( notifyAllSubscribers ) when an event occurs.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 23/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Observer: The Observer interface declares a method ( notifyMe ) that


subjects call to notify observers of any change in state.

package observer;

import java.util.ArrayList;
import java.util.List;

public class YoutubeChannel implements Subject{

private String name;


private List<Observer> subscribers = new ArrayList<>();

public YoutubeChannel(String name) {


this.name = name;
}

public String getName() {


return name;
}

@Override
public void addSubscriber(Observer observer) {
subscribers.add(observer);
}

@Override
public void removeSubscriber(Observer observer) {
subscribers.remove(observer);
}

@Override
public void notifyAllSubscribers(YoutubeEvent event) {
for(Observer observer: subscribers) {
observer.notifyMe(getName(), event);
}
}
}

Concrete Subject: The YoutubeChannel class implements the Subject

interface. It maintains a list of subscribers and notifies them when a new


https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 24/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

event occurs.

package observer;

public class YoutubeSubscriber implements Observer{


private String name;

public YoutubeSubscriber(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

@Override
public void notifyMe(String youtubeChannelName, YoutubeEvent event) {
System.out.println("Dear " + getName() + ", Notification from " + youtub
}
}

Concrete Observer: The YoutubeSubscriber class implements the Observer

interface. It defines the behavior to be performed when notified by a


subject.

public class ObserverMain {


public static void main(String[] args) throws InterruptedException {
YoutubeChannel myChannel = new YoutubeChannel("MyChannel");

Observer john = new YoutubeSubscriber("John");


Observer bob = new YoutubeSubscriber("Bob");
Observer tom = new YoutubeSubscriber("Tom");

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 25/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

myChannel.addSubscriber(john);
myChannel.addSubscriber(bob);
myChannel.addSubscriber(tom);

myChannel.notifyAllSubscribers(new YoutubeEvent(EventType.NEW_VIDEO, "De


myChannel.removeSubscriber(tom);
System.out.println();
Thread.sleep(5000);
myChannel.notifyAllSubscribers(new YoutubeEvent(EventType.LIVE_STREAM, "

}
}

Main Class: The ObserverMain class contains the main method where we
test our implementation. It creates a YoutubeChannel instance, adds
subscribers to it, notifies them of new video event, and removes one of
the subscribers and again notifies them of a live stream event.

// output
Dear John, Notification from MyChannel: NEW_VIDEO on Design patterns
Dear Bob, Notification from MyChannel: NEW_VIDEO on Design patterns
Dear Tom, Notification from MyChannel: NEW_VIDEO on Design patterns

Dear John, Notification from MyChannel: LIVE_STREAM on JAVA for beginners


Dear Bob, Notification from MyChannel: LIVE_STREAM on JAVA for beginners

By using the Observer design pattern, the YouTube channel can easily notify
all its subscribers whenever a new video is uploaded without tightly coupling
the channel and its subscribers. This promotes a more flexible and
maintainable design.

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 26/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

In conclusion, design patterns are indispensable tools for Java developers,


offering proven solutions to recurring design problems and promoting code
reusability, maintainability, and scalability. By understanding and
implementing these patterns effectively, developers can craft robust,
flexible, and easily maintainable software solutions. While mastering design
patterns requires practice and experience, the benefits they bring to
software development are invaluable. Whether you’re working on a small
project or a large-scale enterprise application, leveraging design patterns
empowers you to write cleaner, more efficient code and ultimately become a
more proficient Java developer.

So guys, we have reached the end of this article, Thank you for taking the
time to read this article! I hope you found the information helpful and
gained some valuable insights into the topic. From understanding what
design patterns are to exploring real-world examples of design patterns,
we’ve covered a lot.

In addition to exploring the design patterns discussed here, I invite you to


delve into other insightful articles I’ve written on various Java programming
topics. If you’re interested in optimizing code performance, please check out
my other articles.

OOP explained in JAVA

SOLID principles explained in JAVA

Stream APIs in JAVA

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 27/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Generics in JAVA

If you found my articles useful, please consider giving it claps and sharing it
with your friends and colleagues.

Keep learning, exploring, and creating amazing things with JAVA!

Happy coding!

-Dharshi Balasubramaniyam-

Observer Pattern Design Patterns Java Software Development Programming

Written by Dharshi Balasubramaniyam Follow

236 Followers · Writer for Javarevisited

BSc (hons) in Software Engineering, UG, University of Kelaniya, Sri Lanka.

More from Dharshi Balasubramaniyam and Javarevisited


https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 28/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

Dharshi Balasubramaniyam in Javarevisited ThinkSystem in Javarevisited

SOLID principles explained in JAVA Why you shouldn’t use


SOLID principles are one of the object- LocalDateTime (to avoid…
oriented approaches used in software… Avoid complex production issues caused by
misusing Java LocalDateTime. Find out whic…

8 min read · Nov 4, 2023 10 min read · Feb 3, 2024

163 350 6

Varsha Das in Javarevisited Dharshi Balasubramaniyam

How does YouTube stream millions Beginner’s Guide to Generics in


of videos daily? Java
System design guide with handwritten math Imagine you’re running a grocery store, and
calculations you want to organize your shelves to hold…

16 min read · Mar 12, 2024 7 min read · Apr 5, 2024

605 9 31

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 29/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

See all from Dharshi Balasubramaniyam See all from Javarevisited

Recommended from Medium

Dharshi Balasubramaniyam in Javarevisited Ajay Rathod

SOLID principles explained in JAVA Cisco Java Developer Interview


SOLID principles are one of the object- Transcript 2024(Java,Spring-…
oriented approaches used in software… “Hello folks, I am jotting down the full tech
interview round for a Java developer position…

8 min read · Nov 4, 2023 12 min read · Apr 14, 2024

163 199 1

Lists

General Coding Knowledge Coding & Development


20 stories · 1142 saves 11 stories · 576 saves

Stories to Help You Grow as a Leadership


Software Developer 49 stories · 301 saves

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 30/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

19 stories · 1000 saves

Dr Milan Milanović Jake Page

When to use GraphQL, gRPC, and The guide to Git I never had.
REST? 🩺 Doctors have stethoscopes.
Building APIs is one of the most important
tasks for developers in modern engineering.…

11 min read · Apr 8, 2024 13 min read · Apr 11, 2024

636 4 3.1K 25

Matheus Araujo Vikas Taank

Clean Architecture with Spring Java Streams -Interview Questions


Boot Let's look at some examples for stream
Optimizing agile and maintainable software processing and the questions that I have bee…
development through clean architecture and…

8 min read · Apr 8, 2024 · 3 min read · 4 days ago

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 31/32
4/25/24, 2:34 PM Mastering Design Patterns in Java | by Dharshi Balasubramaniyam | Javarevisited | Feb, 2024 | Medium

169 4 18

See more recommendations

https://medium.com/javarevisited/mastering-design-patterns-in-java-1e39194ac480 32/32

You might also like