Factory Method


To me this just seem to be a band-aid fix for OOP shortcomings.

Look at this example found on geekforgeeks:

Groovy
interface Notification {
    void notifyUser()
}

class SMSNotification implements Notification {
    @Override
    void notifyUser() {
        System.out.println("Sending an SMS notification")
    }
}

class EmailNotification implements Notification {
    @Override
    void notifyUser() {
        System.out.println("Sending an e-mail notification")
    }
}

class PushNotification implements Notification {
    @Override
    void notifyUser() {
        System.out.println("Sending a push notification")
    }
}

class NotificationFactory {
    Notification createNotification(String channel) {
        if (channel == null || channel.isEmpty())
            return null
        switch (channel) {
            case "SMS":
                return new SMSNotification()
            case "EMAIL":
                return new EmailNotification()
            case "PUSH":
                return new PushNotification()
            default:
                throw new IllegalArgumentException("Unknown channel "+channel)
        }
    }
}

class NotificationService {
    static void main(String[] args) {
        NotificationFactory notificationFactory = new NotificationFactory()
        Notification notification = notificationFactory.createNotification("SMS")
        notification.notifyUser()
    }
}

How is this any better than:

Clojure
(defmulti notify-user identity)

(defmethod notify-user :sms [_]
  (print "Sending a SMS notification."))

(defmethod notify-user :email [_]
  (print "Sending an e-mail notification."))

(defmethod notify-user :push [_]
  (print "Sending a push notification."))

(defmethod notify-user :default [channel]
  (throw (IllegalArgumentException. (str "Unknown channel " channel))))

(notify-user :sms)

There are several other ways of doing that in Clojure, but I my go to would be multi-methods because all the cases are clearly separated. That's 50 lines of Groovy/Java vs 15 in Clojure.

Another advantage is that people consuming libraries with multi-methods can extend them by providing a new implementation:

Clojure
(defmethod notify-user :vr-headset []
  (print "Sending an annoying notification to the VR headset."))

With Factory Method every time you add a new implementation you have to change the factory to include this new implementation.