聚合与组合

我很难理解 UML 中组合和聚合之间的区别。有没有人能给我提供一个好的比较和对比他们之间?我还想学习识别它们在代码和/或看一个简短的软件/代码示例中的区别。

编辑: 我问这个问题的部分原因是因为我们正在工作中进行的反向文档活动。我们已经编写了代码,但是我们需要回过头来为代码创建类关系图。我们只是想正确地捕捉这些联系。

85326 次浏览

Composition implies that the child objects share a lifespan with the parent. Aggregation doesn't. For example, a chess board is composed of chess squares - the chess squares don't really exist without the board. However, a car is an aggregation of parts - a car exhaust is still a car exhaust if it's not part of a car at the time.

The distinction between aggregation and composition depends on context.

Take the car example mentioned in another answer - yes, it is true that a car exhaust can stand "on its own" so may not be in composition with a car - but it depends on the application. If you build an application that actually has to deal with stand alone car exhausts (a car shop management application?), aggregation would be your choice. But if this is a simple racing game and the car exhaust only serves as part of a car - well, composition would be quite fine.

Chess board? Same problem. A chess piece doesn't exist without a chess board only in certain applications. In others (like that of a toy manufacturer), a chess piece can surely not be composed into a chess board.

Things get even worse when trying to map composition/aggregation to your favorite programming language. In some languages, the difference can be easier to notice ("by reference" vs. "by value", when things are simple) but in others may not exist at all.

And one last word of advice? Don't waste too much time on this issue. It isn't worth it. The distinction is hardly useful in practice (even if you have a completely clear "composition", you may still want to implement it as an aggregation due to technical reasons - for example, caching).

The example I learned was fingers to the hand. Your hand is composed of fingers. It owns them. If the hand dies, the fingers die. You can't "aggregate" fingers. You can't just go grab extra fingers and attach and detach them from your hand at will.

The value here, from a design viewpoint, is often related to object lifespan as another poster said. Say you have a Customer and they have an Account. That Account is a "composed" object of the customer (at least, in most contexts I can think of). If you delete the Customer, the Account has no value on it's own so it would be deleted as well. The reverse is often true on object creation. Since an Account only has meaning in the context of a Customer, you'd have Account creation occur as part of Customer creation (or, if you do it lazily, it'd be part of some Customer transaction).

It's useful in design to think about what objects own (compose) other objects vs. ones that just reference (aggregate) other objects. It can help determine where the responsibility lies for object creation/cleanup/updates.

As far as in the code, it's often hard to tell. Most everything in code is an object reference so it may not be obvious whether the referenced object is composed (owned) or aggregated.

In code terms, composition usually suggests that the containing object is responsible for creating instances of the component*, and the containing object holds the only long-lived references to it. So if the parent object gets de-referenced and garbage-collected, so will the child.

so this code...

Class Order
private Collection<LineItem> items;
...
void addOrderLine(Item sku, int quantity){
items.add(new LineItem(sku, quantity));
}
}

suggests that LineItem is a component of Order - LineItems have no existence outside of their containing order. But the Item objects aren't constructed in the order - they're passed in as needed, and continue to exist, even if the shop has no orders. so they're associated, rather than components.

* n.b. the container is responsible for instanciating the component, but it might not actually call new...() itself - this being java, there's usually a factory or two to go through first!

The conceptual illustrations provided in other answers are useful, but I'd like to share another point I've found helpful.

I've gotten some mileage out of UML for code generation, for source code or DDL for relational database. There, I have used composition to indicate that a table has a non-nullable foreign key (in the database), and a non-nullable "parent" (and often "final") object, in my code. I use aggregation where I intend a record or object to be able to exist as an "orphan", not attached to any parent object, or to be "adopted" by a different parent object.

In other words, I've used the composition notation as a shorthand to imply some extra constraints that might be needed when writing code for the model.

The example that I like: Composition: Water is a part-of a Pond. (Pond is a composition of water.) Aggregation: Pond has ducks and fish (Pond aggregates ducks and fish)

As you can see I have bolded "part-of" and "has", as these 2 phrases can typically point to what kind of a connection exists between the classes.

But as pointed out by others, many times whether the connection is a composition or an aggregation depends on the application.

Composition and Aggregation are types of associations. They are very closely related and in terms of programming there does not appear to be much of a difference between the two. I will try to explain the difference between these two by java code examples

Aggregation: The object exists outside the other, is created outside, so it is passed as an argument (for example) to the constructor. Ex: People – car. The car is created in a different context and then becomes a person property.

// code example for Aggregation:
// reference existing HttpListener and RequestProcessor
public class WebServer {
private HttpListener listener;
private RequestProcessor processor;
public WebServer(HttpListener listener, RequestProcessor processor) {
this.listener = listener;
this.processor = processor;
}
}

Composition: The object only exists, or only makes sense inside the other, as a part of the other. Ex: People – heart. You don’t create a heart and then pass it to a person. Instead, the heart is created when the human is created.

// code example for composition:
// create own HttpListener and RequestProcessor
public class WebServer {
private HttpListener listener;
private RequestProcessor processor;
public WebServer() {
this.listener = new HttpListener(80);
this.processor = new RequestProcessor(“/www/root”);
}
}

Explained here with an example Difference between Aggregation and Composition

As a rule of thumb: enter image description here

class Person {
private Heart heart;
private List<Hand> hands;
}


class City {
private List<Tree> trees;
private List<Car> cars
}

In composition (Person, Heart, Hand), "sub objects" (Heart, Hand) will be destroyed as soon as Person is destroyed.

In aggregation (City, Tree, Car) "sub objects" (Tree, Car) will NOT be destroyed when City is destroyed.

The bottom line is, composition stresses on mutual existence, and in aggregation, this property is NOT required.

It's so difficult to do a difference between aggregate relation and composite relation, but I'm going to take some examples, We have a house and rooms, here we have a composite relation, room it's a part of the house , and room life started with house life's and Will finish when house life's finish, room it's a part of the house, we talk about composition, like country and capital, book and pages. For aggregate relation example, take team and players, player can exist without team, and team is a group of players, and player life can started before team life's, if we speak about programming, we can create players and after we Will create team, but for composition no, we create room s inside of house . Composition ----> composite|composing. Aggregation -------> group | element

Let's set the terms. The Aggregation is a metaterm in the UML standard, and means BOTH composition and shared aggregation, simply named shared. To often it is named incorrectly "aggregation". It is BAD, for composition is an aggregation, too. As I understand, you mean "shared".

Further from UML standard:

composite - Indicates that the property is aggregated compositely, i.e., the composite object has responsibility for the existence and storage of the composed objects (parts).

So, University to cathedras association is a composition, because cathedra doesn't exist out of University (IMHO)

Precise semantics of shared aggregation varies by application area and modeler.

I.e., all other associations can be drawn as shared aggregations, if you are only following to some principles of yours or of somebody else. Also look here.

Consider human body parts like kidney, liver, brain. If we try to map concept of composition and aggregation here, it would be like:

Before the advent of body parts transplantation like that of kidney's and liver's, these two body parts were in composition with human body and cannot exist isolation with human body.

But after the advent of body part transplantation, they can be transplanted in another human body, so these parts are in aggregation with human body as their existence in isolation with human body is possible now.

It's amazing how much confusion exists about the distinction between the part–whole association concepts aggregation and composition. The main problem is the widespread misunderstanding (even among expert software developers and among the authors of UML) that the concept of composition implies a life-cycle dependency between the whole and its parts such that the parts cannot exist without the whole. But this view ignores the fact that there are also cases of part–whole associations with non-shareable parts where the parts can be detached from, and survive the destruction of, the whole.

In the UML specification document, the definition of the term "composition" has always implied non-shareable parts, but it has not been clear what is the defining characteristic of "composition", and what is merely an optional characteristic. Even in the new version (as of 2015), UML 2.5, after an attempt to improve the definition of the term "composition", it remains still ambiguous and doesn't provide any guidance how to model part–whole associations with non-shareable parts where the parts can be detached from, and survive the destruction of, the whole as opposed to the case where the parts cannot be detached and are destroyed together with the whole. They say

If a composite object is deleted, all of its part instances that are objects are deleted with it.

But at the same time they also say

A part object may be removed from a composite object before the composite object is deleted, and thus not be deleted as part of the composite object.

This confusion points to an incompleteness of the UML definition, which does not account for lifecycle dependencies between components and composites. It's therefore important to understand how the UML definition can be enhanced by introducing a UML stereotype for <<inseparable>> compositions where components cannot be detached from their composite, and, thus, have to be destroyed whenever their composite is destroyed.

Composition

As Martin Fowler has explained, the main issue for characterizing composition is that "an object can only be the part of one composition relationship". This is also explained in the excellent blog post UML Composition vs Aggregation vs Association by Geert Bellekens. In addition to this defining characteristic of a composition (to have exclusive, or non-shareable, parts), a composition may also come with a life-cycle dependency between the composite and its components. In fact, there are two kinds of such dependencies:

  1. Whenever a component must always be attached to a composite, or, in other words, when it has a mandatory composite, as expressed by the "exactly one" multiplicity at the composite side of the composition line, then it must either be re-used in (or re-attached to) another composite, or destroyed, when its current composite is destroyed. This is exemplified by the composition between Person and Heart, shown in the diagram below. A heart is either destroyed or transplanted to another person, when its owner has died.
  2. Whenever a component cannot be detached from its composite, or, in other words, when it is inseparable, then, and only then, the component has to be destroyed, when its composite is destroyed. An example of such a composition with inseparable parts is the composition between Person and Brain.

Person-Brain-Heart

In summary, life-cycle dependencies only apply to specific cases of composition, but not in general, they are therefore not a defining characteristic.

The UML spec states: "A part may be removed from a composite instance before the composite instance is deleted, and thus not be deleted as part of the composite instance." In the example of a CarEngine composition, as shown in the following diagram, it's clearly the case that the engine can be detached from the car before the car is destroyed, in which case the engine is not destroyed and can be re-used. This is implied by the zero or one multiplicity at the composite side of the composition line.

enter image description here

The multiplicity of a composition's association end at the composite side is either 1 or 0..1, depending on the fact if components have a mandatory composite (must be attached to a composite) or not. If components are inseparable, this implies that they have a mandatory composite.

Aggregation

An aggregation is another special form of association with the intended meaning of a part–whole relationship, where the parts of a whole can be shared with other wholes. For instance, we can model an aggregation between the classes DegreeProgram and Course, as shown in the following diagram, since a course is part of a degree program and a course can be shared among two or more degree programs (e.g. an engineering degree could share a C programming course with a computer science degree).

enter image description here

However, the concept of an aggregation with shareable parts doesn't mean much, really, so it does not have any implications on the implementation and many developers therefore prefer not to use the white diamond in their class diagrams, but just model a plain association instead. The UML spec says: "Precise semantics of shared aggregation varies by application area and modeler".

The multiplicity of an aggregation's association end at the whole side may be any number (*) because a part may belong to, or shared among, any number of wholes.