2014-02-06 3 views
0

Просто пытаюсь улучшить мое использование OO в Python и мне интересно о композиции.Python composition

Скажем, например, у вас есть следующие классы:

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 

И инициализирует их

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

Если вы хотите получить доступ к желток, он лучше цепи это как в

bkfast.eggs.yolk 

Или получить к нему доступ через недвижимость

bkfast.yolk 

Вторая версия использует меньше цепочки, хотя все еще делает это за кулисами. В то время как первый показывает вам, что именно происходит. Есть ли предпочтительный метод для этого?

EDIT: Я положил свойство желтка, что он имеет цвет. Если вы хотите получить этот цвет с завтрака, лучше ли иметь свойство завтрака, которое называет свойство яиц или напрямую проникает в сам желток? Или это не имеет значения, поскольку это за кулисами?

+3

http://en.wikipedia.org/wiki/Law_of_Demeter - используйте последний вариант –

+0

http://www.python.org/dev/peps/pep-0020/ Zen of Python: Явный лучше, чем неявный , Простой лучше, чем сложный. – Cilyan

+0

Я бы сказал, что вы должны использовать метод геттера. – 2rs2ts

ответ

3

Надуманные классы каким-то образом мутны. Это зависит от того, что вы пытаетесь сделать, или конкретно о том, как определяется граф объектов, с которым вы работаете. Скачок от breakfast до yolk неестественен ... вы вряд ли прыгаете прямо к ребенку желтка из совокупности завтрака.

В этом случае договор, вероятно, будет, что завтрак будет доставить egg объект, так это то, что ты вернешься, а затем получить желток оттуда при необходимости (но тогда это только вовлекает egg объекта ... breakfast

Если вам почему-то захотелось последовательно захватить желток, вы должны использовать делегирование. Вы никогда не захотите, чтобы ваш код клиента заботился о том, что ему нужно или нужно (Закон Демета выше) , и вы никогда не хотите иметь ничего, кроме определенной и управляемой утечки API, на клиентский код.

Более разумный пример Предположим, что у вас есть яйца в разных формах с завтраком, и это может произойти из тарелки или маленькой отварной яичной подставки или из стекла, «скалистого» стиля.В этом случае клиентский код по-прежнему просто хочет яйцо, поэтому вы хотите использовать делегирование и вытащить яйцо из соответствующего тарелки, подставки или стеклянного ребенка.

Приходит к определению того, что именно вы подвергаете клиенту, и убедитесь, что любой багаж или детали реализации обрабатываются и абстрагируются принимающим объектом. Вы всегда хотите работать с точки зрения того, что вы доставляете, а не оттуда.

+0

Спасибо за ответ. Вместо того, чтобы, предположительно, надуманный пример завтрака, у меня есть класс Container, который действует как контейнер для структуры данных дерева (у которой есть собственное дерево классов). Это дерево имеет root_node. Я хочу скрыть работу Дерева с клиентского кода, и поэтому у контейнера есть утилиты для доступа к нему. Это имеет смысл для меня. –

+0

Имеет ли значение, как контейнер обращается к корневому узлу? то есть сам корневой узел имеет свойство «значение», и клиент должен это знать. Контейнер имеет свойство «root_value» для предоставления этой функции. Имеет ли значение, если это свойство root_value вызывает нечто вроде 'self.tree.root_node.value' или вызывает свойство дерева, которое также является root_value, и таким образом возвращает' self.tree.root_value'? –

+0

Это снова зависит от того, что вы разрабатываете. Самый короткий ответ - не переучивать, поэтому, если вы не подвергаете объект за пределами данного экземпляра, вам не нужно беспокоиться об этом. Если вам нужно беспокоиться об этом ... если 'tree' выставляется в другом месте и вы путешествуете от реализации к API, то к нему должны применяться те же принципы, что и выше. Если это случай, то я бы сказал, что вам нужно также использовать разумную делегацию там, потому что, судя по образцу, клиентский код не должен даже заботиться о том, чтобы это дерево. –

2

На мой взгляд, для этого конкретного примера лучше получить доступ к нему через свойство bkfast.yolk, потому что тогда у вас есть свобода изменения основной реализации желтка.

0

От The Zen of Python

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

мне это означает, что ваш пример не имеет смысла без конкретной задачи. Если вам нужно составить, составите. Если вам это не нужно, не делайте этого. Подумайте о , что означает вашего интерфейса, держите его простых и явно.

Какой же желток завтрака, во всяком случае?