The refactored code implements the Observer Pattern, a behavioral design pattern. It gives an object a subscription list, so many other objects can be told whenever something happens to it.
1. How the Observer Pattern Solves the Problem
By introducing a formal subscription mechanism, the Subject (the YouTube Channel) no longer depends on the Observers (Subscribers). Each side has its own job. The channel only deals with its own changes. The subscribers decide how to notify.
Problem in Old Approach
How Observer Pattern Solves It
Channel is tightly coupled with notification logic
Each subscriber handles its own notification via the update() method.
Not extensible for new notification types
You can add new subscriber classes (e.g., SMS, Slack) without modifying existing code.
No reusability of logic
Notification logic sits inside reusable subscriber classes, not inside the channel.
SRP Violation (Upload + Notify in one class)
Upload logic stays in YouTubeChannel; notification logic is external.
Difficult to manage large numbers of subscribers
The subscribe() and unsubscribe() methods add and remove subscribers at runtime.
2. Key Improvements
Dynamic Subscriptions: Subscribers can be added (subscribe) or removed (unsubscribe) at runtime.
Encapsulation: The YouTubeChannel no longer knows email addresses or app usernames. It only holds a list of Subscriber objects and calls update on each.
Adherence to SOLID:
Open/Closed Principle: You can add new subscriber types, and the YouTubeChannel class stays unchanged.
Single Responsibility Principle: Managing videos and managing notifications are now separate responsibilities.
3. Structural Breakdown
Component
Responsibility
Subject Interface (Channel)
Lists the methods for adding, removing and notifying observers.
Concrete Subject (YouTubeChannel)
Holds the data observers care about. When it changes, it notifies its observers.
Observer Interface (Subscriber)
Declares the update method that every object to be notified must have.
Concrete Observers (EmailSubscriber, etc.)
Implements update to react when the subject changes.
4. Summary of the "Subscription Model"
The Observer Pattern works like a Newspaper Subscription. The publisher (Subject) does not know who reads the paper. It only has a list of addresses. When a new edition is ready, it sends a copy to everyone on the list. To stop receiving it, you remove yourself from the list. The publisher's main job, printing news, stays the same.
1package DesignPatterns.BehaviouralPatterns.ObserverPattern.After;2import java.util.*;34/**5 * 1. THE OBSERVER INTERFACE6 * This defines the 'Contract'. Any object that wants to listen to7 * the channel must implement this interface.8 */9interface Subscriber {10 // The subject calls this method to push updates to the observer11 void update(String videoTitle);12}1314/**15 * 2. CONCRETE OBSERVERS16 * These classes implement the actual notification logic (Email, SMS, App).17 * The Subject doesn't need to know these classes exist.18 */19class EmailSubscriber implements Subscriber {2021 private String email;2223 public EmailSubscriber(String email) {24 this.email = email;25 }2627 @Override28 public void update(String videoTitle) {29 System.out.println(30 "Email sent to " + email + ": New video uploaded - " + videoTitle31 );32 }33}3435class MobileAppSubscriber implements Subscriber {3637 private String username;3839 public MobileAppSubscriber(String username) {40 this.username = username;41 }4243 @Override44 public void update(String videoTitle) {45 System.out.println(46 "In-app notification for " +47 username +48 ": New video - " +49 videoTitle50 );51 }52}5354/**55 * 3. THE SUBJECT INTERFACE56 * Defines how to manage the lifecycle of a subscription.57 */58interface Channel {59 void subscribe(Subscriber subscriber);60 void unsubscribe(Subscriber subscriber);61 void notifySubscribers(String videoTitle);62}6364/**65 * 4. CONCRETE SUBJECT66 * Maintains a dynamic list of observers. It is now completely agnostic67 * to how notifications are sent.68 */69class YouTubeChannel implements Channel {7071 // Dynamic list allows adding/removing subscribers at runtime72 private List<Subscriber> subscribers = new ArrayList<>();73 private String channelName;7475 public YouTubeChannel(String channelName) {76 this.channelName = channelName;77 }7879 @Override80 public void subscribe(Subscriber subscriber) {81 subscribers.add(subscriber);82 }8384 @Override85 public void unsubscribe(Subscriber subscriber) {86 subscribers.remove(subscriber);87 }8889 @Override90 public void notifySubscribers(String videoTitle) {91 // Broadcasters the update to everyone on the list92 for (Subscriber subscriber : subscribers) {93 subscriber.update(videoTitle);94 }95 }9697 /**98 * BUSINESS LOGIC99 * When the state changes (upload), we simply trigger the notification loop.100 */101 public void uploadVideo(String videoTitle) {102 System.out.println(channelName + " uploaded: " + videoTitle + "\n");103 notifySubscribers(videoTitle);104 }105}106107class Main {108109 public static void main(String[] args) {110 YouTubeChannel tuf = new YouTubeChannel("takeUforward");111112 // RUNTIME FLEXIBILITY:113 // We can create and add any number of different observers114 // without ever touching the YouTubeChannel class again.115 tuf.subscribe(new MobileAppSubscriber("raj"));116 tuf.subscribe(new EmailSubscriber("rahul@example.com"));117118 tuf.uploadVideo("Observer-Pattern-Tutorial");119120 // Dynamic Unsubscribe121 // tuf.unsubscribe(someSubscriber);122 }123}124