package factorymethod; public abstract class NotificationSender { // THE factory method — this is the one thing subclasses override. // It returns a Notification (the Product interface), never a concrete class. protected abstract Notification createNotification(); // The shared workflow — marked final so subclasses cannot change it. // It calls createNotification() to get the right notification, // then runs the same steps every time regardless of which channel was created. public final void notify(String recipient, String message) { Notification notification = createNotification(); // delegate creation System.out.println("Sending " + notification.getType() + " notification..."); notification.send(recipient, message); // use the Product interface System.out.println("Delivered."); } // Shared retry logic — works for all channels without change public void notifyWithRetry(String recipient, String message, int maxRetries) { for (int attempt = 1; attempt <= maxRetries; attempt++) { try { notify(recipient, message); return; // success — exit } catch (Exception e) { System.err.printf("Attempt %d failed: %s%n", attempt, e.getMessage()); } } throw new RuntimeException("All " + maxRetries + " attempts failed"); } }