cloning an Observable

Discussion in 'Java' started by Josef Garvi, May 26, 2004.

  1. Josef Garvi

    Josef Garvi Guest

    I have trouble cloning a descendant of Observable.

    I would like to make a deep copy, so I've overridden the clone() method so
    that it clones all fields correctly.

    However, my new clone gets the same observer connections as the original.
    What is worse, if I try to disconnect the observers from my clone by
    writing something like:

    protected Object clone() throws CloneNotSupportedException {
    MyObject cl = (MyObject)super.clone();
    System.out.println("Observers before: " + countObservers());
    cl.deleteObservers();
    System.out.println("Observers after: " + countObservers());
    return cl;
    }

    (the two println commands display the number of observers connected to my
    *original* object)

    ....I lose all the connections from my Observers to my original object as
    well. in other words, the cloned object does not seem to be capable of
    holding an observer list of its own....?
    Any way to get around this?

    TIA

    --
    Josef Garvi

    "Reversing desertification through drought tolerant trees"
    http://www.eden-foundation.org/

    new income - better environment - more food - less poverty
    Josef Garvi, May 26, 2004
    #1
    1. Advertising

  2. Josef Garvi wrote:

    > I have trouble cloning a descendant of Observable.
    >
    > I would like to make a deep copy, so I've overridden the clone() method
    > so that it clones all fields correctly.


    Apparently not. Or alternatively, perhaps you prefer an unusual
    definition of "correctly."

    > However, my new clone gets the same observer connections as the original.
    > What is worse, if I try to disconnect the observers from my clone by
    > writing something like:
    >
    > protected Object clone() throws CloneNotSupportedException {
    > MyObject cl = (MyObject)super.clone();
    > System.out.println("Observers before: " + countObservers());
    > cl.deleteObservers();
    > System.out.println("Observers after: " + countObservers());
    > return cl;
    > }
    >
    > (the two println commands display the number of observers connected to
    > my *original* object)
    >
    > ...I lose all the connections from my Observers to my original object as
    > well. in other words, the cloned object does not seem to be capable of
    > holding an observer list of its own....?


    Your clone is sharing its observer list with the original. This is
    happening because during the cloning process, the reference to this
    object was copied from the original into the clone. Instead you want
    the clone to get its own object.

    > Any way to get around this?


    Your clone() method is wrong. Without studying the matter, I cannot say
    for certain whether it is even possible to write a correct one in a case
    such as this. Considering that you do not want the clone to receive the
    observers of the original, it may be that you are pursuing a suboptimal
    strategy in the first place -- if you explain the bigger picture then
    you might get some apropos suggestions.


    John Bollinger
    John C. Bollinger, May 26, 2004
    #2
    1. Advertising

  3. Josef Garvi

    Josef Garvi Guest

    John C. Bollinger wrote:


    >> I would like to make a deep copy, so I've overridden the clone()
    >> method so that it clones all fields correctly.

    >
    >
    > Apparently not. Or alternatively, perhaps you prefer an unusual
    > definition of "correctly."


    You're right - apparently not. I meant that the fields that *I* have added
    to the Observable in my subclass are copied correctly. The problem is that
    the fields in Observable, my ancestor, do not deep copy....


    > Your clone is sharing its observer list with the original. This is
    > happening because during the cloning process, the reference to this
    > object was copied from the original into the clone. Instead you want
    > the clone to get its own object.


    Yep, that's precisely my goal.


    >> Any way to get around this?

    >
    >
    > Your clone() method is wrong. Without studying the matter, I cannot say
    > for certain whether it is even possible to write a correct one in a case
    > such as this.


    See bottom for a simple, compilable example.


    > Considering that you do not want the clone to receive the
    > observers of the original, it may be that you are pursuing a suboptimal
    > strategy in the first place -- if you explain the bigger picture then
    > you might get some apropos suggestions.


    I have a class that draws a complex view onto a frame, scaling it according
    to the size of the frame. I also want to print this view, but then need to
    modify a couple of settings in it. I could change the settings back and
    forth in my view, but that would cause the frame to look funny for a
    second. I could also implement an echo switch that i turn off when changing
    the settings for the printout and turn on when I've reset the settings...
    But what seemed like the neatest solution to me was to clone the view,
    adjust the settings in my clone, print it and discard it.




    public class DeepCopyTest extends Observable implements Cloneable {

    // dummy observer class.
    static class TestObserver implements Observer {
    public void update(Observable arg0, Object arg1) {
    // do something....
    }
    }

    /* Create an object, connect an observer and clone it. */
    public static void main(String[] args) {
    TestObserver observer = new DeepCopyTest.TestObserver();
    DeepCopyTest original = new DeepCopyTest();
    original.addObserver(observer);
    System.out.println("Observers on original before clone: "
    + original.countObservers());
    try {
    DeepCopyTest clone = (DeepCopyTest)original.clone();
    } catch (CloneNotSupportedException e) {
    // doesn't matter, it suports cloneable.
    e.printStackTrace();
    }
    System.out.println("Observers on original after clone: "
    + original.countObservers());
    }

    public DeepCopyTest() {
    super();
    }

    protected Object clone() throws CloneNotSupportedException {
    DeepCopyTest cl = (DeepCopyTest)super.clone();
    cl.deleteObservers(); /* the clone should not have any
    observers connected to it */
    return cl;
    }

    }


    --
    Josef Garvi

    "Reversing desertification through drought tolerant trees"
    http://www.eden-foundation.org/

    new income - better environment - more food - less poverty
    Josef Garvi, May 27, 2004
    #3
  4. Josef Garvi

    Josef Garvi Guest

    Josef Garvi wrote:

    >> Your clone is sharing its observer list with the original. This is
    >> happening because during the cloning process, the reference to this
    >> object was copied from the original into the clone. Instead you want
    >> the clone to get its own object.

    >
    >
    > Yep, that's precisely my goal.


    I figured out a way of solving it. I duplicated the code for the Observable
    class (naming it CloneableObservable), and added the following clone()
    method to it:

    protected Object clone() throws CloneNotSupportedException {
    CloneableObservable co = (CloneableObservable)super.clone();
    co.obs = (Vector)obs.clone();
    return co;
    }

    Now it gets it's own observer list, and everything works fine.

    Does doing this violate Sun's license in any way?


    --
    Josef Garvi

    "Reversing desertification through drought tolerant trees"
    http://www.eden-foundation.org/

    new income - better environment - more food - less poverty
    Josef Garvi, May 27, 2004
    #4
  5. Josef Garvi

    P.Hill Guest

    Josef Garvi wrote:
    [...]
    >>> Your clone is sharing its observer list with the original.

    >
    > I figured out a way of solving it. I duplicated the code for the
    > Observable class (naming it CloneableObservable), and added the
    > following clone() method to it:
    >
    > protected Object clone() throws CloneNotSupportedException {
    > CloneableObservable co = (CloneableObservable)super.clone();
    > co.obs = (Vector)obs.clone();
    > return co;
    > }


    Why couldn't you just subclass Obeservable to create CloneableObservable
    which contains the better clone() method with the clone of the obs vector?

    -Paul
    P.Hill, May 27, 2004
    #5
  6. Josef Garvi

    Josef Garvi Guest

    P.Hill wrote:
    > Josef Garvi wrote:
    > [...]
    >
    > Why couldn't you just subclass Obeservable to create CloneableObservable
    > which contains the better clone() method with the clone of the obs vector?


    Because the obs field is private.... :-(

    But I did actually subclass it AND paste the original code (plus my added
    method) into the subclass. That way, it still connects to the interface
    Observer... :)

    --
    Josef Garvi

    "Reversing desertification through drought tolerant trees"
    http://www.eden-foundation.org/

    new income - better environment - more food - less poverty
    Josef Garvi, May 27, 2004
    #6
  7. Josef Garvi wrote:

    > Josef Garvi wrote:
    >
    >>> Your clone is sharing its observer list with the original. This is
    >>> happening because during the cloning process, the reference to this
    >>> object was copied from the original into the clone. Instead you want
    >>> the clone to get its own object.

    >>
    >>
    >>
    >> Yep, that's precisely my goal.

    >
    >
    > I figured out a way of solving it. I duplicated the code for the
    > Observable class (naming it CloneableObservable), and added the
    > following clone() method to it:
    >
    > protected Object clone() throws CloneNotSupportedException {
    > CloneableObservable co = (CloneableObservable)super.clone();
    > co.obs = (Vector)obs.clone();
    > return co;
    > }
    >
    > Now it gets it's own observer list, and everything works fine.


    That'll do it.

    > Does doing this violate Sun's license in any way?


    I am not a lawyer. If you plan to distribute this software or use it
    other than for personal, non-commercial purposes, then I suggest you
    carefully read the license that accompanies the JDK from which you
    excerpted the source to judge for yourself. (Personal, non-commercial
    uses potentially run afoul of licensing restrictions too, but they are
    much less likely to land you in the middle of a lawsuit.) The source
    file in question may also bear copyright / licensing information.

    A safer path is to implement your own version of Observable from
    scratch. It's not that hard. Just don't refer to the Sun source code
    while you do, or you may end up right back where you started.

    --
    John Bollinger
    John C. Bollinger, May 27, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. JKV

    Observable class

    JKV, Sep 2, 2003, in forum: Java
    Replies:
    1
    Views:
    386
    William Brogden
    Sep 2, 2003
  2. Jeffrey Drew

    Observable approach feedback requested

    Jeffrey Drew, Oct 9, 2003, in forum: Java
    Replies:
    0
    Views:
    426
    Jeffrey Drew
    Oct 9, 2003
  3. Timo Nentwig
    Replies:
    1
    Views:
    500
    xarax
    Oct 27, 2003
  4. Digital Puer
    Replies:
    4
    Views:
    461
    Dave Benjamin
    Apr 2, 2004
  5. Jason Cavett
    Replies:
    1
    Views:
    507
    Tom Hawtin
    Apr 19, 2007
Loading...

Share This Page