Re: Aggregation vs composition
From: Matthias Hofmann (hofmann_at_anvil-soft.com)
Date: 05/08/04
- Next message: Matthias Hofmann: "Re: Aggregation vs composition"
- Previous message: Ilja Preuß: "Re: Association in UML"
- In reply to: Daniel T.: "Re: Aggregation vs composition"
- Next in thread: Daniel T.: "Re: Aggregation vs composition"
- Reply: Daniel T.: "Re: Aggregation vs composition"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Sat, 8 May 2004 10:54:06 +0200
Daniel T. <postmaster@eathlink.net> schrieb in im Newsbeitrag:
postmaster-1A4757.23184207052004@news1.west.earthlink.net...
> "Matthias Hofmann" <hofmann@anvil-soft.com> wrote:
>
> > Daniel T. <postmaster@eathlink.net> schrieb:
> > >
> > > And believe it or not, I also approve of:
> > >
> > > [A]<#>--->[B]<----[C]
> > >
> > > However, when I see this, I assume that the B objects that C uses are
> > > *not* the same B objects that A contains. If A and C are sharing the
> > > same B objects, then I would ask that the A->B relationship be changed
> > > to aggregation. Would you insist that it stay a Composition?
> >
> > This is the diagram that we are discussing about. I just came up with
> > another example:
> >
> > struct X
> > {
> > int i;
> > };
> >
> > void f( X& x )
> > {
> > x.i = 0;
> > }
> >
> > I think it can be modelled in an analogous fashion:
> >
> > [X]<#>-------------[int]<-------------[f]
> >
> > The difference being that the int that f uses *is* the one contained by
X.
> > And I'd say yes, it should stay a composition. Not only does X destroy
the
> > int, it has no other choice but doing so as it cannot prevent the
> > destruction of its part when X itself gets destroyed.
>
> Given this:
>
> struct A { int b; };
>
> struct C { int* b; C(int* b):b(b) { } };
>
> Now somewhere in the code we have:
>
> A a;
> C c( &a.b );
>
> What object is responsible for making sure that c.b != &a.b before a is
> destroyed?
When the A object goes out of scope, a.b will be destroyed, there's no way A
can prevent that. It can only hope that C is aware of A's lifetime and make
sure that c.b will be reassigned (perhaps NULL) or at least not dereferenced
any more.
> > You can of course decide to implement X like
> >
> > class X
> > {
> > int i;
> >
> > public:
> > SetMember( int value ) { i = value; }
> > };
> >
> > This follows your policy of not returning handles to internal data (or
not
> > letting anyone in your house, as you described it). But what would that
> > change? Calling X::SetMember() is not any safer than accessing the
member
> > directly.
>
> Sure it is:
>
> struct A { int b; };
>
> int main() {
> A* a = new A;
> b = &a.b;
> delete a;
> *b = 5;
> }
>
> The above cannot happen with the class with the private int.
I agree with you here. I wanted to say that using the private int and the
accessor function is not any safer as long as you do the same thing as in my
example (simpy assign to the int). And for this very example, I think that
the diagram shown above expresses the relationship.
> > This is maybe were the misunderstanding lies: I say that the container
has
> > "sole responsibility for the disposition of its parts" because it can
rely
> > on the clients sticking to the rules laid down by the documentation. You
say
> > it cannot destroy the parts at any time because someone will probably
> > violate these rules.
>
> No, I say that because the container is limited as to when it can
> destroy the part (limited by the rules laid down by the documentation)
> it is not solely responsible.
The way I see things, it is the client of the container who is limited as to
how it can use the part. Unless you are arguing that the container cannot
change its behaviour because it cannot update the documentation any more. I
have , of course, assumed that changes in the implementation and/or
behaviour of the whole lead to an update of the documentation, possibly
breaking old client code.
> Another real world example. If you were "solely responsible" for getting
> across the street safely, then even is someone was *trying* to run you
> over, they would have no responsibility in your failure. Fortunatly, you
> are not solely responsible for crossing the street, the cars on the road
> are partly responsible for ensuring you get across safely. Because of
> this shared responsibility, there are rules (documention) laid down
> explaining when and where you can cross the street.
I think I can see your point. The traffic rules are laid down by the
government, not by the car drivers. A car driver cannot change its behaviour
and switch the meanings for a red light and a green light, as everybody else
might not hear about this crucial "update"...
> > However, we maybe do not really contradict each other, as we both say
(if I
> > understand you correctly) that the whole can return handles to internal
data
> > and delete the data at will, as long as it can assume that the clients
stick
> > to these rules.
>
> I agree with everything you say above except for the "at will" part. The
> container must also stick to the rules, it is limited as to *when* it
> can destroy the part. The container no longer is "solely responsible",
> all the objects sharing the part are partly responsible, they *all* must
> adhere to the rules.
Ok, I should not have written "at will", as this is misunderstandable. Of
course the "will" has to be reflected in the documentation, and the object
should not change its will after it has once documented it.
> And in any case the part is being shared and Composition specifies that
> the parts are *not* shared...
Yes, but the UML models the relationship in code. It does not prevent you
from documenting your classes, it even encourages you to do so by supplying
a means to emphasize such pitfalls in diagrams. You can, for example, add a
note in the diagram, refering the reader to the documentation for B's
lifetime.
> > After all, you cannot abolish NULL-pointers just because someone might
> > dereference them...
>
> This is a straw man... When the parts are being shared, the proper
> adornment is aggregation, when they are not it is composition. I'm not
> saying that the parts should never be shared, I'm just saying that if
> they are, then you don't have a composition relationship. Composition
> specifies that the parts are not shared.
The way I understand the UML, sending a message to a part does not mean
sharing it. In the struct X { int i; } example above, i is not shared by f()
and X.
Best regards,
Matthias
- Next message: Matthias Hofmann: "Re: Aggregation vs composition"
- Previous message: Ilja Preuß: "Re: Association in UML"
- In reply to: Daniel T.: "Re: Aggregation vs composition"
- Next in thread: Daniel T.: "Re: Aggregation vs composition"
- Reply: Daniel T.: "Re: Aggregation vs composition"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|