Question

Just trying to improve my OO use in Python and am curious about composition.

Say for example you have the following classes:

Class Breakfast(object):
    __init__(self, eggs):
        self.eggs = eggs

    @property
    def yolk(self):
        return eggs.yolk

    @property
    def yolk_colour(self):
        return eggs.yolk.colour
        OR
        return.eggs.yolk_colour

Class Eggs(object):
    __init__(self, yolk):
        self.yolk = yolk

    @property
    def yolk_colour(self):
        return self.yolk.colour

Class Yolk(object):
    __init__(self, colour):
        self.colour = colour

And initialise them

eggs = Eggs(Yolk("yellow"))
bkfast = Breakfast(eggs)

When you want to access the yolk, is it better to chain it as in

bkfast.eggs.yolk

Or access it via a property

bkfast.yolk

The second version uses less chaining directly, although still does it behind the scenes. Whereas the first one shows you exactly what is going on. Is there a preferred method for this?

EDIT: I've put in a property of yolk that it has a colour. If you want to get that colour from the breakfast, is it better to have a property of breakfast that calls a property of eggs, or directly access the yolk itself? Or does it not matter as it's behind the scenes?

Était-ce utile?

La solution

The contrived classes in some way muddy the issue. It somewhat depends on what you're trying to do, or specifically how the object graph that you're working with is defined. The jump from breakfast to yolk is unnatural...you'd be unlikely to jump directly to the yolk child of the breakfast aggregate.

In this case the contract would likely be that the breakfast would deliver the egg object, so that is what you would return, and then get the yolk from there if needed (but then that only involves the egg object...breakfast stops caring.

If for some reason you did want to consistently grab the yolk, then you should use delegation. You never want your client code to care about more than it has to or should (the Law of Demeter above), and you never want to have anything but the defined and managed API leak to the client code.

A more reasonable example would be supposing that you have eggs in different forms with breakfast, and so it may come from a plate, or a little soft boiled egg stand, or from a glass, "Rocky" style. In that case the client code still just wants the egg, so you'd want to use delegation and fetch the egg out of the appropriate plate, stand, or glass child.

It comes down to defining what it is you are exposing to the client code, and make sure that any baggage or implementation details are handled and abstracted by the receiving object. You always want to work in terms of what you are delivering and not where it is coming from.

Autres conseils

In my opinion for this particular example, It is better to access it via the property bkfast.yolk, because then you have the freedom of changing the underlying implementation of yolk.

From The Zen of Python

Explicit is better than implicit.
Simple is better than complex.

To me it means your example doesn't have sense without a concrete problem. If you need to compose, do compose. If you don't need, don't. Think about the meaning of your interface, keep it simple and explicit.

What the yolk of a breakfast is about, anyway?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top