Reputation: 3331
I am playing around with composition and had a question. Say I have a Fruit
and Apple
classes where apple
is a passthrough to a fruit
public class Apple {
Fruit fruit;
}
Fruit has a bunch of member fields such as skin
, color
etc. What is the best practice when we instantiate an Apple
object? Should I construct the fruit
object internally without exposing any indication that the Apple contains a Fruit object? i.e. when constructing the Apple object, I call apple.setColor()
which sets the fruit.setColor()
property internally. Or, should I construct the full fruit
object and during the apple
instantiation, pass in the fruit
object fully constructed?
Upvotes: 1
Views: 331
Reputation: 441
It really depends on how you are modeling your problem. But I think paying attention to encapsulation principle of OOP would help us. Encapsulation wants us to hide information about an object within itself, or, in other words give each object responsibility of performing its own actions.
Back to your question, first let us consider the case in which Fruit
object is only an underlying data structure (i.e. Apple
object is a complete superset of Fruit
in responsibilities). In this case, if you ask developers to construct the Fruit
object for you and pass it along, you are exposing your internal responsibilities, and you may let the developer access to unwanted data or behavior.
Fruit f = new Fruit();
f.doSomethingPrivate(); // This is not intended for an Apple to be set externally
Apple a = new Apple(f); // Now the Fruit object may not comply with Apple definition
It is now obvious that in some cases, the above example is exactly the thing you want to do. Consider now the composition pattern (see here). In composition you have a container which is not anticipated to encapsulate the responsibilities for its contained elements.
A very simple example can be a university course, in which some students enroll and has an instructor:
public class Course {
private Person instructor;
private Person[] students;
}
Here, it is not the Course
object responsibility to expose instructor or students behaviors. Instead, the container object may have getInstructor()
and setInstructor()
methods and let the developer decide about the contained elements in the composition.
Upvotes: 2
Reputation: 837
Seems weird to have a Fruit inside an Apple. I would use inheritance in this case. Or at least have Apple implement a Fruit interface and hide the delegate member. So for constructing the Fruit member, that means: Do it internally inside the Apple constructor. This is because of the is-a relationship between the Apple and Fruit concepts.
In other cases it might be usefull to pass a pre constructed instance for the member in the constructor. That would be the case e.g. if more apples refer to the same fruit instance. In general that would be more of a has-a or uses relation between Apple and Fruit
Upvotes: 0