One object passing members to another class, modifying values

Discussion in 'Java' started by craigslist.jg@gmail.com, May 10, 2007.

  1. Guest

    Hi,

    Let's say I have an instance of ClassA, which has an instance variable
    holding a list of numbers as an array (for simplicity's sake). Let's
    call this instance variable, arrayA. Let's assume all instVars are
    public.

    Now, ClassB needs to have access to arrayA, and delete some members
    within the array.

    Based on OOP principles, what's the better / cleaner implementation
    for this?

    1. Create a couple of instVars in ClassB:
    instVar1 : reference to ArrayA
    instVar2: new array keeping track of deleted members

    Within ClassA, instantiate ClassB, and set instVar1.
    When ClassB is done, within ClassA, delete members from arrayA based
    on instVar2.

    ClassA doStuff()

    classB = new ClassB
    classB.instVar1 = arrayA
    classB.compileRemovedItems()
    arrayA.removeAll(classB.instVar2)

    ClassB compileRemovedItems()

    instVar2 = setRemovedItems()

    2. As in (1), create a couple of instVars, but instantiate the
    instVar1 within classB

    ClassA doStuff()

    classB = new ClassB
    classB.compileRemovedItems()
    arrayA.removeAll(classB.instVar2)

    ClassB compileRemovedItems()

    instVar1 = classA.arrayA
    instVar2 = setRemovedItems()

    3. From ClassB, access arrayA directly, and remove the items there.

    ClassA doStuff()

    classB = new ClassB
    classB.compileRemovedItems()

    ClassB compileRemovedItems()
    instVar1 = classA.arrayA
    instVar2 = setRemovedItems()
    instVar1.removeAll(instVar2)


    With 1, classB has no dependencies on classA, but I have to keep on
    setting instVar1 at every point I need to call compileRemovedItems.

    With 2, classB sets instVar1 from classA so I save that extra step.

    3 is even more dependent on classA, as it is accessing and modifying
    arrayA directly.


    Thanks for reading.
    , May 10, 2007
    #1
    1. Advertising

  2. Z. Guest

    wrote:
    > Let's say I have an instance of ClassA, which has an instance variable
    > holding a list of numbers as an array (for simplicity's sake). Let's
    > call this instance variable, arrayA. Let's assume all instVars are
    > public.
    >
    > Now, ClassB needs to have access to arrayA, and delete some members
    > within the array.
    >
    > Based on OOP principles, what's the better / cleaner implementation
    > for this?


    The proper way is for ClassB to access (read/write/delete) ClassA's
    fields only through public accessor methods of ClassA.

    ClassA should not expose modifiable fields directly and ClassB should
    not keep local copies of ClassA's fields in ClassB.
    Z., May 10, 2007
    #2
    1. Advertising

  3. H. S. Lahman Guest

    Responding to Craigslist.jg...

    > Let's say I have an instance of ClassA, which has an instance variable
    > holding a list of numbers as an array (for simplicity's sake). Let's
    > call this instance variable, arrayA. Let's assume all instVars are
    > public.


    So arrayA is a collection class implementing the R1 relationship in

    1 R1 *
    [ClassA] --------------- [Number]

    > Now, ClassB needs to have access to arrayA, and delete some members
    > within the array.


    If ClassB needs access to those same numbers, they can't be part of the
    ClassA implementation as a fundamental language data structure like an
    array. That's because anything in the ClassA implementation needs to be
    hidden from the outside world, so it would be invisible to ClassB. So
    you really have, at the OOA/D level:

    [CLassA]
    | 1
    |
    | R1
    |
    | *
    [Number]
    | *
    |
    | R2
    |
    | 1
    [ClassB]

    OTOH, making a number a first class object is a bit of overkill. So what
    one really wants is a bit more abstraction:

    [ClassA]
    | 1
    |
    | R1
    |
    | 1
    [NumberList]
    + getNumber(entryID) // e.g., whatever
    + setNumber(entryID, value) // e.g., whatever
    | 1
    |
    | R2
    |
    | 1
    [ClassB]

    Now [NumberList] is a reasonable first class object abstraction to which
    both [ClassA] and [ClassB] have references and those references
    instantiate the R1 and R2 relationships, respectively.

    Note that all this does is take arrayA out of the [ClassA]
    implementation and make it a peer class of both ClassA and ClassB. The
    only trickiness lies in referential integrity (i.e., instantiating the
    relationships as [ClassA] and [ClassB] objects are created). That
    mechanics will depend upon the specific problem in hand, but a "factory"
    objects can encapsulate those sorts of rules.


    *************
    There is nothing wrong with me that could
    not be cured by a capful of Drano.

    H. S. Lahman

    Pathfinder Solutions
    http://www.pathfindermda.com
    blog: http://pathfinderpeople.blogs.com/hslahman
    "Model-Based Translation: The Next Step in Agile Development". Email
    for your copy.
    Pathfinder is hiring:
    http://www.pathfindermda.com/about_us/careers_pos3.php.
    (888)OOA-PATH
    H. S. Lahman, May 10, 2007
    #3
  4. Daniel T. Guest

    wrote:

    > Let's say I have an instance of ClassA, which has an instance variable
    > holding a list of numbers as an array (for simplicity's sake). Let's
    > call this instance variable, arrayA. Let's assume all instVars are
    > public.


    First mistake. Why make such an assumption?

    > Now, ClassB needs to have access to arrayA, and delete some members
    > within the array.


    A particular object of ClassB, or the class itself? Are the members that
    ClassB deletes supposed to also be deleted in the list that the ClassA
    object has?

    > Based on OOP principles, what's the better / cleaner implementation
    > for this?


    If ClassB is not a peer to ClassA then I would likely have the ClassA
    object pass a reference to the array when it creates the ClassB object.
    Then let the ClassB object delete the numbers itself. This way, ClassB
    is in no way dependent on ClassA and can be used by any class that is
    willing and able to pass ClassB an array of numbers.

    The above can tend to obfuscate the code though. A better choice would
    be to have a ClassA object instantiate a ClassB object, and have the
    ClassB object manage the array of numbers.

    [ClassA]--->[ClassB]--->[ArrayA]

    Instead of:

    [ClassA]----->[ClassB]
    | |
    | |
    +->[ArrayA]<-+
    Daniel T., May 11, 2007
    #4
  5. squirrel Guest

    On May 10, 11:42 pm, wrote:
    > Hi,
    >
    > Let's say I have an instance of ClassA, which has an instance variable
    > holding a list of numbers as an array (for simplicity's sake). Let's
    > call this instance variable, arrayA. Let's assume all instVars are
    > public.
    >
    > Now, ClassB needs to have access to arrayA, and delete some members
    > within the array.
    >
    > Based on OOP principles, what's the better / cleaner implementation
    > for this?
    >
    > 1. Create a couple of instVars in ClassB:
    > instVar1 : reference to ArrayA
    > instVar2: new array keeping track of deleted members
    >
    > Within ClassA, instantiate ClassB, and set instVar1.
    > When ClassB is done, within ClassA, delete members from arrayA based
    > on instVar2.
    >
    > ClassA doStuff()
    >
    > classB = new ClassB
    > classB.instVar1 = arrayA
    > classB.compileRemovedItems()
    > arrayA.removeAll(classB.instVar2)
    >
    > ClassB compileRemovedItems()
    >
    > instVar2 = setRemovedItems()
    >
    > 2. As in (1), create a couple of instVars, but instantiate the
    > instVar1 within classB
    >
    > ClassA doStuff()
    >
    > classB = new ClassB
    > classB.compileRemovedItems()
    > arrayA.removeAll(classB.instVar2)
    >
    > ClassB compileRemovedItems()
    >
    > instVar1 = classA.arrayA
    > instVar2 = setRemovedItems()
    >
    > 3. From ClassB, access arrayA directly, and remove the items there.
    >
    > ClassA doStuff()
    >
    > classB = new ClassB
    > classB.compileRemovedItems()
    >
    > ClassB compileRemovedItems()
    > instVar1 = classA.arrayA
    > instVar2 = setRemovedItems()
    > instVar1.removeAll(instVar2)
    >
    > With 1, classB has no dependencies on classA, but I have to keep on
    > setting instVar1 at every point I need to call compileRemovedItems.
    >
    > With 2, classB sets instVar1 from classA so I save that extra step.
    >
    > 3 is even more dependent on classA, as it is accessing and modifying
    > arrayA directly.
    >
    > Thanks for reading.


    If you just want to decouple the dependency of classA and classB, why
    not apply Vistor pattern.
    squirrel, May 11, 2007
    #5
  6. Daniel T. Guest

    squirrel <> wrote:

    > If you just want to decouple the dependency of classA and classB, why
    > not apply Vistor pattern.


    I think that would be a little extreme in this case. Simply removing the
    back-pointer would be enough to do the job.
    Daniel T., May 12, 2007
    #6
  7. AndyW Guest

    On 10 May 2007 08:42:58 -0700, wrote:

    >Hi,
    >
    >Let's say I have an instance of ClassA, which has an instance variable
    >holding a list of numbers as an array (for simplicity's sake). Let's
    >call this instance variable, arrayA. Let's assume all instVars are
    >public.
    >
    >Now, ClassB needs to have access to arrayA, and delete some members
    >within the array.
    >
    >Based on OOP principles, what's the better / cleaner implementation
    >for this?


    I use an OO rule that states "An object should not modify the contents
    of another object, but should request that the other object modify
    itself".

    Its based on the principle of encapsulation.

    One can use 'loose coupling' by using an event mechanism or 'tight
    coupling' by calling a function call defined in the classes public
    interface.


    ----------------
    AndyW,
    Mercenary Software Developer
    AndyW, May 12, 2007
    #7
  8. Same here.
    And preferably use meaningful names when possible, such as addCustomer:,
    removeCustomer: instead of just add:, remove:

    "AndyW" <> schreef in bericht
    news:...
    > On 10 May 2007 08:42:58 -0700, wrote:
    >
    >>Hi,
    >>
    >>Let's say I have an instance of ClassA, which has an instance variable
    >>holding a list of numbers as an array (for simplicity's sake). Let's
    >>call this instance variable, arrayA. Let's assume all instVars are
    >>public.
    >>
    >>Now, ClassB needs to have access to arrayA, and delete some members
    >>within the array.
    >>
    >>Based on OOP principles, what's the better / cleaner implementation
    >>for this?

    >
    > I use an OO rule that states "An object should not modify the contents
    > of another object, but should request that the other object modify
    > itself".
    >
    > Its based on the principle of encapsulation.
    >
    > One can use 'loose coupling' by using an event mechanism or 'tight
    > coupling' by calling a function call defined in the classes public
    > interface.
    >
    >
    > ----------------
    > AndyW,
    > Mercenary Software Developer
    Robin Barendregt, May 12, 2007
    #8
  9. RichardETVS Guest

    While encapsulation is a general rule, and a good one, there can be
    case where it is not the best, in my humble opinion.

    Take an object database like db4o, by example (www.dbf4.com ) . You
    save an object with something like
    "anObjectDataBaseManager.Save(TheObjectIwantToSave). And it is saved,
    even its private fields. To fully load an object, you can use a syntax
    like "ObjectContainer.Activate(TheObjectIwantToFullyLoad,
    int.MaxValue)".

    So, in those cases, the encapsulation is broken. For a data layer, I
    had to something like that. The BO objects ask to the data layer to
    save and update them. I did not want to use .net reflection, so I used
    the Separate Interface Pattern, and with an explicit interface, my BO
    expose all their private fields to the data layer.

    I have to amit my solution has a problem. The user interface layer, in
    C#, asks a reference to the interface module, it seems that in VB it
    is not the case. So, if a developer really want it, he can use the
    explicit interface mechanism to acces private BO fields.



    Richard
    RichardETVS, May 15, 2007
    #9
  10. Ed Guest

    On 15 Maj, 11:51, RichardETVS <> wrote:
    > While encapsulation is a general rule, and a good one, there can be
    > case where it is not the best, in my humble opinion.
    >
    > Take an object database like db4o, by example (www.dbf4.com) . You
    > save an object with something like
    > "anObjectDataBaseManager.Save(TheObjectIwantToSave). And it is saved,
    > even its private fields. To fully load an object, you can use a syntax
    > like "ObjectContainer.Activate(TheObjectIwantToFullyLoad,
    > int.MaxValue)".
    >
    > So, in those cases, the encapsulation is broken. For a data layer, I
    > had to something like that. The BO objects ask to the data layer to
    > save and update them. I did not want to use .net reflection, so I used
    > the Separate Interface Pattern, and with an explicit interface, my BO
    > expose all their private fields to the data layer.
    >
    > I have to amit my solution has a problem. The user interface layer, in
    > C#, asks a reference to the interface module, it seems that in VB it
    > is not the case. So, if a developer really want it, he can use the
    > explicit interface mechanism to acces private BO fields.
    >
    > Richard


    Hej, Richard,

    While I fully agree that there is always a case for breaking a rule in
    special circumstances (even encapsulation), could I just note a humble
    alternative to your approach, though I lack your insight into the
    problem?

    Firstly, encapsulation can help insulate a class from changes in
    another class.

    In the solution you have above, I presume that the following line
    means: create an instance of TheObjectIwantToFullyLoad and set its
    MaxValue accordingly:
    "ObjectContainer.Activate(TheObjectIwantToFullyLoad, int.MaxValue)"

    If this is the case, then we can consider what happens when
    TheObjectIwantToFullyLoad gets a new field variable, let's call it:
    String name.

    Now, both TheObjectIwantToFullyLoad must change (to add this new
    variable) and - more importantly - ObjectContainer must change, as it
    must now call:
    "ObjectContainer.Activate(TheObjectIwantToFullyLoad, int.MaxValue,
    string.name)"

    This, we note, is the price of breaking encapsulation.

    The question is: could there be a way to respect encapsulation so
    that
    ObjectContainer isn't affected by any changes to the internals of
    TheObjectIwantToFullyLoad?

    An answer could be to have TheObjectIwantToFullyLoad (and any
    serialisable object) responsible for its own data serialisation. It
    could have a method save(BitStream stream). This method is called by
    ObjectContainer and it passes in the stream that will be written to
    the file system.

    It is then up to TheObjectIwantToFullyLoad to convert all its private
    data to a bit-stream representation and write this data to the bit-
    stream.

    The reverse is true when reading a bit-stream from the file system:
    TheObjectIwantToFullyLoad itself will be resonsible for inspecting
    the bit-stream and converting it back to an int and a string value.

    Now, changes to TheObjectIwantToFullyLoad do not affect the
    ObjectContainer.

    ..ed

    --
    www.EdmundKirwan.com - Home of The Fractal Class Composition.

    Download Fractality, free Java code analyzer:
    www.EdmundKirwan.com/servlet/fractal/frac-page130.html
    Ed, May 16, 2007
    #10
  11. Lew Guest

    Ed wrote:
    > While I fully agree that there is always a case for breaking a rule in
    > special circumstances (even encapsulation), could I just note a humble
    > alternative to your approach, though I lack your insight into the
    > problem?


    Aren't you the diplomat?

    > An answer could be to have TheObjectIwantToFullyLoad (and any
    > serialisable object) responsible for its own data serialisation. It
    > could have a method save(BitStream stream). This method is called by
    > ObjectContainer and it passes in the stream that will be written to
    > the file system.


    Or you could use the built-in serialization in Java. Keywords like
    "transient" help control what gets written or not.

    Whatever serialization you use, bear in mind the advice upthread that
    [de]serialization is a whole other public interface, like a public
    constructor, and commits the class to a lifetime of engineering for
    serialization. Joshua Bloch covers this in depth in /Effective Java/,
    mandatory reading for the OP with respect to this issue.

    (N.b., I am responding via clj.programmer, so I focus on Java solutions. I
    have no idea why the cross-posts to comp.object and cl.smalltalk are there,
    but I am ignoring that aspect.)

    --
    Lew
    Lew, May 16, 2007
    #11
  12. Ed Guest

    On 16 Maj, 15:06, Lew <> wrote:

    > (N.b., I am responding via clj.programmer, so I focus on Java solutions. I
    > have no idea why the cross-posts to comp.object and cl.smalltalk are there,
    > but I am ignoring that aspect.)
    >
    > --
    > Lew


    Ah, frac (as Starbuck loves to say) I didn't even notice that it was
    cross-posted. Now I feel like a spammer.

    I need a bath ...

    ..ed

    --
    www.EdmundKirwan.com - Home of The Fractal Class Composition.

    Download Fractality, free Java code analyzer:
    www.EdmundKirwan.com/servlet/fractal/frac-page130.html
    Ed, May 16, 2007
    #12
  13. Lew Guest

    [OT] Cattlecar Belackluster (was: One object passing members to anotherclass, modifying values)

    Ed wrote:
    > Ah, frac (as Starbuck loves to say) I didn't even notice that it was
    > cross-posted. Now I feel like a spammer.



    Nice Battlestar Galactica reference. Ain't the new Starbuck so very well
    realized?

    --
    Lew
    Lew, May 16, 2007
    #13
  14. Ed Guest

    Re: Cattlecar Belackluster (was: One object passing members to another class, modifying values)

    On 16 Maj, 16:31, Lew <> wrote:
    > Ed wrote:
    > > Ah, frac (as Starbuck loves to say) I didn't even notice that it was
    > > cross-posted. Now I feel like a spammer.

    >
    > Nice Battlestar Galactica reference. Ain't the new Starbuck so very well
    > realized?
    >
    > --
    > Lew


    Copy that.

    Who'd have thought Face would go for a sex-change?

    ..ed

    --

    www.EdmundKirwan.com - Home of The Fractal Class Composition
    Ed, May 17, 2007
    #14
  15. RichardETVS Guest

    > In the solution you have above, I presume that the following line
    > means: create an instance of TheObjectIwantToFullyLoad and set its
    > MaxValue accordingly:
    > "ObjectContainer.Activate(TheObjectIwantToFullyLoad, int.MaxValue)"


    No, I was not clear, sorry. intMaxSize is a parameter and set the
    deepness of the activation. If you write 0, it will get the object and
    it values fields, but not references. int.MaxValue in a C# constant,
    so I fix the activation depth at the maximum I can get, so I fully
    load the object in memory, with all his fields, even if a field is a
    list of objects, by example. This is not usual, as you could load a
    pretty heavy object, like "hospital", with all the rooms, employees,
    patients, etc.

    The important thing is that I do not take special precautions for
    saving the object or loading it. I just use save(anObject) and it is
    saved, even with its private fields. And if I modify the object, by
    adding a field or anything else, I'll just use save(anObject). So, you
    see, maybe there is a price for breaking encapsulation, but it is not
    here. By the way, as this database is free with source code, you can
    check by yourself at www.db4o.com.

    Now, I do not claim that for my own application my solution is the
    best. It works, but probably I'll explore some other solutions, and
    that could be serialization, thanks for the tip ;) .

    Cordially

    Richard
    RichardETVS, May 29, 2007
    #15
    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. Brahmam
    Replies:
    3
    Views:
    549
    Francois Beaussier
    Jan 11, 2006
  2. =?Utf-8?B?Q2hyaXM=?=

    Error passing values from one pahge to another

    =?Utf-8?B?Q2hyaXM=?=, May 13, 2005, in forum: ASP .Net
    Replies:
    8
    Views:
    1,034
    =?Utf-8?B?Q2hyaXM=?=
    May 16, 2005
  3. CoolPint
    Replies:
    8
    Views:
    957
    Jeff Schwab
    Dec 14, 2003
  4. hdixon
    Replies:
    3
    Views:
    628
    hdixon
    Jul 9, 2006
  5. Robert Cohen
    Replies:
    3
    Views:
    253
    Andrew Durstewitz
    Jul 15, 2003
Loading...

Share This Page