This class calls for a distinction between object identity and object state. Made this distinction, it becomes possible to share the same state across different objects upon copy operations. When an object is updated, a new state representation is bound to that object, while the other objects can still share the previous state. This way we can have shallow copy with the semantics of deep copy. This can result in dramatically reduced memory footprint when:
For example, think of a class
R that represents a rectangle in
the plane with
4 integer fields
x, y, w, h,
and say you want to use instances of this class to describe an ROI (region of
interest) selection in a given image 3D-stack composed of
planes each plane would contain a rectangle selection and all those
selections would make up your ROI. Let's assume that the initial selection is
a discrete 3D-rectangle that spans all planes in the stack you would
have one rectangle per plane, every rectangle would have exactly the same
s[x=0, y=0, w=3, h=4]. Moreover, let's assume that
you will have to modify slightly this initial ROI in order to get the final
selection for example by resizing/moving a couple of rectangles within
the selection. Now, when you start off with the initial selection, you could
decide to clone an initial master object whose state is
this way, you can later modify one of the copies without affecting the
others. However, because Java makes no distinction between object
identity and state, you would have in memory
100 copies of the same logical state
while you actually only need one.
The purpose of this class is to help you save memory in situations like that just described by approximating the semantics of the well known Handle/Body and Counted Body idioms often found in C++ programs. A given class abstraction is implemented by two actual classes which replicate the same class interface. One class, the Handle, takes on the role of an object identifier and forwards all calls to the other class, the Body, which implements the actual functionality. Clients can only access instances of the Handle which can all share the same Body object whenever appropriate.
The way this works in our case is pretty easy. An Handle class extends this
Handle class and provides a reference to an instance of
the corresponding Body class. The concrete Handle class exposes the same
interface as its corresponding Body (this is not an absolute requirement, but
usually an implementation trade-off) and has no state in fact,
the state is hold by the associated Body object. The Handle just forwards to
the Body any call that only reads the Body's state. However, it must call the
breakSharing protected method before
forwarding any call that modifies the Body's state. It is crucial that
Handle classes stick to this rule. In fact, the
copy method simply rebinds a new
Handle to the
existing Body, so subclasses must notify any incumbent change to the Body's
state for the
Handle to break state sharing. Lastly, it's also
fundamental that the Body class implements the
correctly for all this to work properly.
|Modifier||Constructor and Description|
Subclasses use this constructor to specify the Body instance this handle will be paired up with.
|Modifier and Type||Method and Description|
Subclasses must call this method before forwarding any call that modifies the Body's state.
Returns a deep copy of this object.
Returns a reference to the Body object that is currently paired up with this handle.
protected Handle(Copiable body)
body- Reference to the Body object. Mustn't be
protected Object getBody()
breakSharingmethod has been invoked. For this reason, subclasses mustn't cache a reference to the object returned by this method. Moreover, subclasses must never leak out a reference to the returned Body object.
protected final void breakSharing()
public final Object copy()
Copyright © 2017 The University of Dundee & Open Microscopy Environment. All Rights Reserved.