Pattern, Abstract Factory / Factory

Hans Hübner hans.huebner at gmail.com
Sun Feb 7 08:25:54 UTC 2021


DI Frameworks live on a different plane than most of the micro-patterns in
the GoF class:  They try to solve the problem that when using a framework,
composing the components that a specific framework application needs can be
difficult and complex.  This is done by annotating the application
component that makes use of a framework feature (using configuration files
or, more recently, source code annotations), and then having the framework
runtime collect the dependencies from the annotations to build the right
set of components.  Effectively, instead of statically linking the
application to the framework, the linking is performed at run-time and, as
the linking information is richer than in traditional linking systems (i.e.
an application-level annotation instead of just a function name), it can do
a lot of things that are typically aspects of systems written in
dynamically typed programming languages.

The applicability of dependency injection really depends on the complexity
of the framework that is being talked about.  In simple, and in particular
in framework-less systems, one does not really need a framework-specific,
configurable, run-time linking component.  Most Lisp systems do not
actually depend on a framework, and Lisp - as a dynamic language - provides
for plenty of run-time features that can be used to achieve what is the
magic sauce in dependency injection frameworks.  One may want to
standardize how component linkage is performed in a large Lisp system, of
course, but the challenges would be different as much of the tooling to
perform the actual work is available right away.

The same can be said about many of the patterns that are used in the OO and
Java world, of course.  They often provide solution architectures to
problems that are hard to solve given the constraints of - in particular -
Java, and for which trivially easy solutions can be devised in Lisp on the
fly without having to resort to a named pattern.

-Hans

Am So., 7. Feb. 2021 um 08:59 Uhr schrieb Marco Antoniotti <
marco.antoniotti at unimib.it>:

> OK.
>
> procedure foo is
>    x : Integer := 42;
> begin
>     ...
> end
>
>
> Now foo depends on the hardwired '42' (as is should, one may argue :) ).
> And we are not even talking about "classes" or Lisp here.
>
> Have I boiled down to the essentials?  How do you do the rolling eyes
> emoticon?
>
> All the best
>
> Marco
>
>
> On Sat, Feb 6, 2021 at 10:50 PM Pascal Bourguignon <pjb at informatimago.com>
> wrote:
>
>> 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__
>>
>>
>
> --
> Marco Antoniotti, Associate Professor         tel. +39 - 02 64 48 79 01
> DISCo, Università Milano Bicocca U14 2043 http://bimib.disco.unimib.it
> Viale Sarca 336
> I-20126 Milan (MI) ITALY
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/pro/attachments/20210207/0e0b686f/attachment-0001.html>


More information about the pro mailing list