How to "force" my object never been changed by other other objectsusing it?

Discussion in 'Java' started by Chris Dollin, Feb 8, 2007.

  1. Chris Dollin

    Chris Dollin Guest

    Re: How to "force" my object never been changed by other other objects using it?

    www wrote:

    > I have a class, Data.java. Once an object of this class is created,
    > several other kind objects will use it. For example:
    >
    > Data myDataObj = new Data(...//params);
    >
    > UserA userA = new UserA(myDataObj); //pass the object to another object.
    > double ave = userA.getAverage();
    >
    > UserB userB = new UserB(myDataObj);
    > ...
    >
    > I want myDataObj state never been modified by users.


    Make all its variables private (possibly: protected) and provide
    no setters. [Recurse if necessary.]

    --
    Chris "electric hedgehog" Dollin
    "We did not have time to find out everything we wanted to know."
    - James Blish, /A Clash of Cymbals/
    Chris Dollin, Feb 8, 2007
    #1
    1. Advertising

  2. Chris Dollin

    www Guest

    Hi,

    I have a class, Data.java. Once an object of this class is created,
    several other kind objects will use it. For example:

    Data myDataObj = new Data(...//params);

    UserA userA = new UserA(myDataObj); //pass the object to another object.
    double ave = userA.getAverage();

    UserB userB = new UserB(myDataObj);
    ....


    I want myDataObj state never been modified by users. Right now, I just
    open my eyes widely to make sure that my code does not do it. I am
    wondering if I can use some key words to enforce it, like:

    final Data myDataObj = new Data(...); //my feeling this is wrong: it
    just make sure the reference myDataObj (the memory address in heap being
    referenced) cannot be changed. Or, the street address cannot be changed.
    But the house can be modified. Am I correct?


    How about ...?

    public class UserA()
    {
    public UserA(final Data data) //constructor
    {
    ...//code
    }

    }

    Thank you.
    www, Feb 8, 2007
    #2
    1. Advertising

  3. Chris Dollin

    www Guest

    Chris Dollin wrote:

    >
    > Make all its variables private (possibly: protected) and provide
    > no setters. [Recurse if necessary.]
    >


    Sorry. My posting was not clear. I don't want Data.java completely
    immutable. Occasionally, I want to change the object state, like:

    dataObj.setName("bar"); //before it was "foo", now it is bar

    My first posting and my purpose is: I don't want dataObj being modified
    by other objects without my awareness. Such change could be burried in
    UserA class' some method somewhere and I am totally not aware of it.
    www, Feb 8, 2007
    #3
  4. Chris Dollin

    Chris Dollin Guest

    Re: How to "force" my object never been changed by other other objects using it?

    www wrote:

    > Chris Dollin wrote:
    >
    >> Make all its variables private (possibly: protected) and provide
    >> no setters. [Recurse if necessary.]

    >
    > Sorry. My posting was not clear. I don't want Data.java completely
    > immutable. Occasionally, I want to change the object state, like:
    >
    > dataObj.setName("bar"); //before it was "foo", now it is bar
    >
    > My first posting and my purpose is: I don't want dataObj being modified
    > by other objects without my awareness. Such change could be burried in
    > UserA class' some method somewhere and I am totally not aware of it.


    Make all its variables private (possibly: protected) and provide
    setters which report the change to you (or your representative code).

    If you make the setters [package] protected, and put your "safe" code
    in the same package, users can't see the setter anyway.

    If you don't mind the value changing, then I'm not sure why you mind
    someone else changing it. But then, I don't know what your design goals
    are.

    --
    Chris "electric hedgehog" Dollin
    "A facility for quotation covers the absence of original thought." /Gaudy Night/
    Chris Dollin, Feb 8, 2007
    #4
  5. Chris Dollin

    www Guest

    For another better example to show my point:

    public class Car
    {
    final private Engine engine = new Engine(); //even the final word here
    may does not serve my purpose

    public void drive()
    {
    ...//code
    }

    public void stop()
    {
    ...//code
    }

    public void turnLeft()
    {
    ...//code
    }

    ...

    }

    I do not want Engine being completely immutable. I want to be able to
    tune or fix Engine sometimes by myself. But I do NOT want when Car is
    doing something(driving, stopping, or ...), Car is tuning or modifying
    Engine. That is dangerous!
    www, Feb 8, 2007
    #5
  6. Chris Dollin

    Oliver Wong Guest

    Re: How to "force" my object never been changed by other other objects using it?

    "www" <> wrote in message
    news:eqffv3$smt$...
    > Hi,
    >
    > I have a class, Data.java. Once an object of this class is created,
    > several other kind objects will use it. For example:
    >
    > Data myDataObj = new Data(...//params);
    >
    > UserA userA = new UserA(myDataObj); //pass the object to another object.
    > double ave = userA.getAverage();
    >
    > UserB userB = new UserB(myDataObj);
    > ...
    >
    >
    > I want myDataObj state never been modified by users. Right now, I just
    > open my eyes widely to make sure that my code does not do it. I am
    > wondering if I can use some key words to enforce it, like:
    >
    > final Data myDataObj = new Data(...); //my feeling this is wrong: it just
    > make sure the reference myDataObj (the memory address in heap being
    > referenced) cannot be changed. Or, the street address cannot be changed.
    > But the house can be modified. Am I correct?


    You're right that "final" won't do it. I'm assuming that you want to
    make Data immutable mainly for reducing bugs, and not for security purposes.

    Simply provide two interfaces for your Data object, one which provides
    getters, and one which provides setters.

    public interface ReadableData {
    int getX();
    }

    public class Data implements ReadableData {
    private int x;
    public int getX() {
    return this.x;
    }

    public void setX(int newValue) {
    this.x = newValue;
    }
    }

    And when you want to make your object immutable, upcast it from Data to
    ReadableData:

    Data myDataObj = new Data();
    ReadableData immutableViewOfMyDataObj = myDataObj;
    immutableViewOfMyDataObj.setX(5); /*This causes a compile error, setX() is
    not defined on the interface.*/

    If you have "malicious programmers" on your team, they can get around
    this by downcasting from ReadableData to Data, which is why I say this only
    works for bug detecting and not security. If you need something stronger
    than this, then you'll probably need to make proxy classes which can read
    from the original data object, but never provides a mean to write to it.

    - Oliver
    Oliver Wong, Feb 8, 2007
    #6
  7. Chris Dollin

    Oliver Wong Guest

    Re: How to "force" my object never been changed by other other objects using it?

    "www" <> wrote in message
    news:eqfimb$tm3$...
    > For another better example to show my point:
    >
    > public class Car
    > {
    > final private Engine engine = new Engine(); //even the final word here
    > may does not serve my purpose
    >
    > public void drive()
    > {
    > ...//code
    > }
    >
    > public void stop()
    > {
    > ...//code
    > }
    >
    > public void turnLeft()
    > {
    > ...//code
    > }
    >
    > ...
    >
    > }
    >
    > I do not want Engine being completely immutable. I want to be able to tune
    > or fix Engine sometimes by myself. But I do NOT want when Car is doing
    > something(driving, stopping, or ...), Car is tuning or modifying Engine.
    > That is dangerous!


    With this new information, I have a different recommendation. I had thought
    you wanted to pass off an object which *you* can mutate, but no one else
    could. Now it sounds like you want an object which can mutate, but only in
    certain states:

    public class Car {
    public boolean isSafeToTune() {
    return !driving && !turning;
    }

    public boolean isSafeToTurn() {
    return !driving && ! tuning;
    }

    /**
    * PRECONDITIONS: none
    * POSTCONDITIONS: driving
    */
    public void drive() {
    driving = true;
    }

    /**
    * PRECONDITIONS: none
    * POSTCONDITIONS: !driving
    */
    public void stop() {
    driving = false;
    }

    /**
    * PRECONDITIONS: isSafeToTurn()
    * POSTCONDITIONS: turning
    */
    public void turnLeft() {
    if (!isSafeToTurn()) {
    throw new IllegalStateException();
    }
    turning = true;
    }

    /**
    * PRECONDITIONS: isSafeToTune()
    * POSTCONDITIONS: car is tuned.
    */
    public void tune() {
    if (!isSafeToTune()) {
    throw new IllegalStateException();
    }
    /*tune car somehow*/
    }
    }

    Users of your class will have to read the javadocs carefully and understand
    when and why they are allowed to call certain methods, and not other
    methods.

    - Oliver
    Oliver Wong, Feb 8, 2007
    #7
  8. Chris Dollin

    Chris Uppal Guest

    Re: How to "force" my object never been changed by other other objects using it?

    www wrote:

    > I want myDataObj state never been modified by users.


    You can't do it with any combination of "final" flags (unless you want to make
    your object completely immutable -- and even then you can't /quite/ manage it).

    The closest you can come is to hand out an immutable proxy for the object
    instead of the object itself. E.g.

    public interface Data
    {
    int getWidth();
    String getName();
    int[] getMoreData();
    }

    public class RealData
    implements Data
    {
    private int m_width;
    private String m_name;
    private int[] m_moreData;

    public int getWidth() { return m_width; }
    public String getName() { return m_name; }
    public int[] getMoreData() { return m_moreData; }
    public void setWidth(int width) { m_width = width; }
    public void setName(String name) { m_name = name; }
    public void setMoreData(int[] data) { m_moreData = data; }

    public Data asImmutableData() { return new ImmutableData(); }

    class ImmutableData
    implements Data
    {
    public int getWidth() { return RealData.this.getWidth(); }
    public String getName() { return RealData.this.getName(); }
    public int[] getMoreData() { return
    RealData.this.getMoreData().clone(); }
    }
    }

    Note that there may be nothing to gain in making RealData public, and there may
    be nothing to gain in making it implement Data and have public get/set methods.
    But I've made it public here to illustrate how, even if it is public, a user of
    the object returned by asImmutableData() cannot change it.

    Note also the call to clone() in the immutable version of getMoreData() -- we
    don't want to hand out a reference to the real array, since arrays (or
    references to arrays) cannot be made immutable.


    As something of an aside, I would be tempted to add asImmutableData() to the
    Data interface, and make ImmutableData.asImmutableData() just
    return this;
    The idea is that something can pass on an immutable proxy for a possibly
    mutable object to a third party by using asImmutableData() whether originally
    had a reference to a RealData or an ImmutableData.


    A simpler solution, and in many cases a better solution, is just not to worry
    about it. If the other code changes your object then it must have been given
    the relevant access permissions -- and if you've given it that then you
    obviously trust it not to do anything stupid.

    -- chris
    Chris Uppal, Feb 8, 2007
    #8
  9. Chris Dollin

    Eric Sosman Guest

    www wrote On 02/08/07 11:21,:
    > For another better example to show my point:
    >
    > public class Car
    > {
    > final private Engine engine = new Engine(); //even the final word here
    > may does not serve my purpose
    >
    > public void drive()
    > {
    > ...//code
    > }
    >
    > public void stop()
    > {
    > ...//code
    > }
    >
    > public void turnLeft()
    > {
    > ...//code
    > }
    >
    > ...
    >
    > }
    >
    > I do not want Engine being completely immutable. I want to be able to
    > tune or fix Engine sometimes by myself. But I do NOT want when Car is
    > doing something(driving, stopping, or ...), Car is tuning or modifying
    > Engine. That is dangerous!


    public void tuneOrFix() {
    if (engineIsRunning())
    throw new IllegalStateException("pphhht!");
    removeSparkPlugs();
    ...
    }

    You might also want to modify some of the other methods:

    public void drive() {
    if (maintenanceInProgress())
    throw new IllegalStateException(
    "not while it's on the lift!");
    if (! engineIsRunning())
    start();
    ...
    }

    --
    Eric Sosman, Feb 8, 2007
    #9
    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. Replies:
    1
    Views:
    669
    Rosanne
    Oct 11, 2005
  2. Soren Kuula
    Replies:
    1
    Views:
    437
    Henry S. Thompson
    Dec 1, 2005
  3. Kevin
    Replies:
    4
    Views:
    409
    Irrwahn Grausewitz
    Oct 17, 2003
  4. student
    Replies:
    7
    Views:
    370
    student
    Jan 22, 2012
  5. moon
    Replies:
    1
    Views:
    116
    David Dorward
    Jul 9, 2003
Loading...

Share This Page