I have run into this design "problem" several times and I have a
nagging feeling I'm not handling it correctly :
Let's say you have created a class which is to act as a "template" for
other instances. I'm going to use an inventory like system as my
example :
(define-class <widget> ()
(width
height
color
cost
name
...
instance-identifier
complicated-structure))
So now <widget> is described, but I want to have many instances of
widget in my program, each distinguished by the content of their
slots, not by the name of their class. For example if <widgets> are
cubes, I will distinguish between red-cubes, blue-cubes, etc...
complicated-structure might be something really ugly, like a JPEG of a
pattern which appears on the outside of the cube.
The thing is, if I just create instances of <widget> I'll end up with
instances which all have their own copy of complicated-structure. For
that matter they will all have their own copy of all the slots, when,
in fact, they should all share the same information. A particular
instance of <widget> is what I call a "template". So to avoid all
this duplication of information, I've been doing this:
Remove the identifier slot from widget and create the following class:
(define-class <widget-instance> ()
(widget ;; a reference to the "template" instance
identifier))
Now I create an instance of <widget-instance> based on a widget of a
particular "construction". The widget slot points to reference of an
instance of <widget>. So I would have instances of <widget-instance>
blue-cube-1, blue-cube-2, etc. which all share a "blue-cube" instance
of class <widget>. Still with me ? The information is now shared
across multiple widgets of the same "type" and I have what I call an
instance of an instance (or an instance of the template).
The things that really bugs me is that data accesses now must go
through another level of indirection. I have to operate on a slot of
the widget-instance instead of on the widget-instance itself even
though my intention is to have, in a way an instance of <widget>.
So, am I missing something ? For someone reason this design approach
doesn't feel right. I have noticed this pattern in both C++ and CLOS
programming and I am thinking that there is probably a better way to
do what I am trying to do. Naturally I'm interested in the best way
using CLOS.
Brian
From: Tim Bradshaw
Subject: Re: instances of classes and instances of instances
Date:
Message-ID: <nkj90cvqgfh.fsf@tfeb.org>
Brian Denheyer <······@deldotd.com> writes:
> The thing is, if I just create instances of <widget> I'll end up with
> instances which all have their own copy of complicated-structure. For
> that matter they will all have their own copy of all the slots, when,
> in fact, they should all share the same information. A particular
> instance of <widget> is what I call a "template". So to avoid all
> this duplication of information, I've been doing this:
>
> Remove the identifier slot from widget and create the following class:
>
> (define-class <widget-instance> ()
> (widget ;; a reference to the "template" instance
> identifier))
>
You can use class slots to do this, though they don't always work as
you'd want I think (in particular in the context of subclassing). In
general this looks pretty close to the `flyweight' pattern that the
design patterns people talk about. I forget how they think you should
do this. I'm hoping to do a CLOS-take on the `gang-of-four' design
patterns book, so if you wait for that ...
--tim
From: Christopher J. Vogt
Subject: Re: instances of classes and instances of instances
Date:
Message-ID: <36F111C2.DAF31208@computer.org>
Brian Denheyer wrote:
>[...]
>
> So now <widget> is described, but I want to have many instances of
> widget in my program, each distinguished by the content of their
> slots, not by the name of their class. For example if <widgets> are
> cubes, I will distinguish between red-cubes, blue-cubes, etc...
> complicated-structure might be something really ugly, like a JPEG of a
> pattern which appears on the outside of the cube.
>
> The thing is, if I just create instances of <widget> I'll end up with
> instances which all have their own copy of complicated-structure.
They won't have their own copy of compilicated-structure, they will each
have their own "pointer" to the same object. If compilicated-strucuture
is some 5MB representation of a JPEG image, then each instance has a pointer
to the same image, the 5MB isn't duplicated in each instance, only the
pointer is duplicated.
>[...]
>
> So, am I missing something ? For someone reason this design approach
> doesn't feel right. I have noticed this pattern in both C++ and CLOS
> programming and I am thinking that there is probably a better way to
> do what I am trying to do. Naturally I'm interested in the best way
> using CLOS.
maybe you could do something like this:
(defvar *compilicated-structure* nil)
(defclass widget()
(complicated-structure))
(defmethod initialize-instance :after ((self widget) &key)
(with-slots (complicated-structure) self
(if (null *compilicated-structure*)
(setf *compilicated-structure* (make-complicated-structure)))
(setf complicated-structure *compilicated-structure*)))
(defun make-complicated-structure ()
(make-array 10000))