What is the logic of composition in object oriented design?

92 views Asked by At

I am confused about the composition (has a) relationship. It is clear to me that for example a car class has a motor class. My problem is about classes they do not own another class logically, but own them physically in order to use them. You have to have a reference or own a class in order to use its methods, but sometimes it doesn't make sense on a logical level. For example, let's say there is a class garbage man and is another class waste container. The garbage man uses the empty method of waste container and in order to use its methods, has a reference to the waste container. Does this mean that garbage man has a (well, multiple) waste container on an object oriented design? I would say garbage man uses waste container, but it confuses me since the garbage man physically has it. Can someone tell me the logic please?

2

There are 2 answers

0
antlersoft On

There are objects you own and objects you have a reference to. If a containing object owns the contained object, it means the containing object is responsible for the contained object's lifecycle -- creating it, disposing of it (if it's an object that can be disposed of). The owner can also pass ownership of a contained object to another object.

An object you have a reference to is an object you can use, but don't own. The owner will typically give you a reference to the object (by passing it as a parameter to a function call, maybe), and guarantees that the object is in a valid state while you have the reference (some environments assist with this by providing automatic garbage collection)

"Has a" relationships may be either owning or reference, and most computer languages don't include explicit support for the reference/ownership distinction, but it is an important concept to keep straight in design. The UML modeling language does model this distinction: ownership indicates a "composite" relationship, while a reference is an "aggregate" relationship.

0
David On

GarbageMan doesn't have a WasteContainer, since a waste container doesn't in any way describe a garbage man or extend its attributes in any way.

I think you're missing an operation here. WasteContainer has an empty() method because that's an action which can be performed on it. But GarbageMan also has an operation. A GarbageMan can performJob(). That is where a WasteContainer comes in. Consider something like this (language-agnostic):

class WasteContainer {
    empty() { ... }
}

class GarbageMan {
    performJob(Collection<WasteContainer> containers) {
        foreach (var container in containers) {
            container.empty();
        }
    }
}

A GarbageMan knows about WasteContainers, since that's part of his job. But he doesn't have WasteContainers because maintaining their state isn't part of his job. He performs an operation on them, but doesn't own them.

This can be further abstracted with the use of an interface. For example:

interface Emptyable {
    empty();
}

class WasteContainer : Emptyable {
    empty() { ... }
}

class GarbageMan {
    performJob(Collection<Emptyable> bins) {
        foreach (var bin in bins) {
            bin.empty();
        }
    }
}

Now GarbageMan is further de-coupled from WasteContainer. There could be many kinds of containers which can be emptied, and a GarbageMan can handle all of them. The operation is performed identically, just supply a collection of containers to the GarbageMan and he does his job.

This seems to more closely model the real-world scenario being observed, as opposed to a GarbageMan owning the state of WasteContainers. There would likely be some Employer which manages which WasteContainers are sent to a particular GarbageMan instance, there may be different Customers who actually own WasteContainers or other kinds of Emptyables, etc.