Композиция. Композиция. Композиция.

Композиция.

Open in new window

Композиция

Композиция - это составление целого из частей.

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

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

Допустим у нас есть класс месенжера, который должен отправлять сообщения, используя разные мессенжеры (telegramm email и пр.).

Можно его описать следующим образом.

class BaseMessanger():

    def send(self, type, message):

        if type == 'email':
            print("Посылаю %s на email" % message)

        if type == 'telegram':
            print("Посылаю %s на telegram" % message)

m = BaseMessanger()
m.send('email','Hello!')

При таком подходе существует ряд проблем.

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

  2. Если у этого класса много наследников, то любая поломка в базовом классе приведет к обрушению всех дочерних.

  3. Такой класс сложно тестировать, например, если в тестах требуется вместо реальной отправки на email сохранить сообщение в файле нам прийдется править базовый класс.

  4. Невозможно изменить способ передачи после создания объекта.

Разрешить эту ситуацию можно композицией.

При этом мы создадим ряд классов (транспортных) на каждый вид доставки и делегируем им процесс отправки.

Далее мы внедрим объект необходимого класса в наш основной класс при инициализации его объекта в конструкторе.

class BaseMessanger(object):


    def __init__(self,message,sender):
        self.message = message
        self.sender = sender

    def send(self):
        self.sender.send(self.message)


class EmailSender():

    def send(self,message):
        print 'I am sending this %s via email' % message

class SkypeSender():

    def send(self,message):
        print 'I am sending this %s via skype' % message

class SmsSender():

    def send(self,message):
        print 'I am sending this %s via sms' % message

email_sender = EmailSender()
message = BaseMessanger('hello',email_sender)
message.send()

Можно указывать транспорт в конструкторе

class Messanger(object):

def __init__(self,message,sender=EmailSender()):

Нужно помнить, что класс EmailSender должен быть определен перед классом Messanger.

email_sender = EmailSender()
message = Messanger('hello')
message.send()
message.sender = SmsSender()
message.send()


>>I am sending this hello via email
>>I am sending this hello via sms

Other topics