Pattern, Abstract Factory / Factory
Pascal Bourguignon
pjb at informatimago.com
Sat Feb 6 21:50:33 UTC 2021
Le 06/02/2021 à 22:37, Manfred Bergmann a écrit :
> You have a class. This class uses some other class.
> But by using or creating an instance of this other class directly you create a dependency on something concrete.
> That’s not what you want, because you might want to replace this with something else if required. For example with a mock or fake implementation in a test.
> ‚Dependency injection‘ allows you to declare this dependency with just an interface/protocol and have some other facility (the dependency injection framework) ‚inject‘ a concrete object at run-time.
> A similar thing could certainly be done by just using a constructor parameter (strategy pattern).
> But I think the important part here is the dependency on just an interface and not on a concrete implementation. For flexibility.
With some code:
;;;------------------------------------------------------------
(defclass used ()
())
(defmethod used-stuff ((self used))
'stuff)
;;; ---
(defclass user ()
((used :reader used)))
(defmethod initialize-instance :after ((self user) &key &allow-other-keys)
(setf (slot-value self 'used) (make-instance 'used #|OOPS,
Dependency!|#)))
(defmethod user-stuff ((self user))
;; Not a real dependency on the used class,
;; it's a dependency on the used-stuff generic function (interface).
(used-stuff (used self)))
;;; ---
(defclass client ()
())
(defmethod create-user ((self client))
;; The class client depends directly on the user class,
;; and indirectly on the used class.
(make-instance 'user))
;;;------------------------------------------------------------
(defclass used ()
())
(defmethod used-stuff ((self used))
'stuff)
;;; ---
(defclass user ()
((used :initarg :used :reader used)))
;; The user class has no more any dependency on the used class.
(defmethod user-stuff ((self user))
;; Not a real dependency on the used class,
;; it's a dependency on the used-stuff generic function (interface).
(used-stuff (used self)))
;;; ---
(defclass client ()
())
(defmethod create-user ((self client))
;; The class client depends explicitely on the user and used classes.
;; But now, the class user doesn't depend directly on the used class;
;; this dependency is injected by the client into the user classe:
(make-instance 'user :used (make-instance 'used)))
;;;------------------------------------------------------------
;; Notably if the client wants the user to use another used class:
(defclass variant-used (used)
())
(defmethod used-stuff ((self variant-used))
'variant-stuff)
(defmethod create-user ((self client))
;; only the client needs to be changed; the user class won't know
;; the difference:
(make-instance 'user :used (make-instance 'variant-used)))
--
__Pascal Bourguignon__
More information about the pro
mailing list