Команда (Транзакция, Action)

Команда (Транзакция, Action)
Это поведенческий паттерн проектирования, который позволяет разделить например интерфейс и бизнес-логику, используя класс, который делегирует бизнес-логике действие, запрашиваемое отправителем команды. Паттерн Команда по сути устанавливает одностороннюю связь от заказчика к исполнителю.
Паттерн Команда (как впрочем и другие паттерны проектирования отношений между отправителем и получателем запросов) ведет к появлению дополнительных классов и усложнению кода.

Реализация паттерна проектирования Команда на python

# coding: utf-8


class Light(object):
    def turn_on(self):
        print 'Включить свет'

    def turn_off(self):
        print 'Выключить свет'


class CommandBase(object):
    def execute(self):
        raise NotImplementedError()


class LightCommandBase(CommandBase):
    def __init__(self, light):
        self.light = light


class TurnOnLightCommand(LightCommandBase):
    def execute(self):
        self.light.turn_on()


class TurnOffLightCommand(LightCommandBase):
    def execute(self):
        self.light.turn_off()


class Switch(object):
    def __init__(self, on_cmd, off_cmd):
        self.on_cmd = on_cmd
        self.off_cmd = off_cmd

    def on(self):
        self.on_cmd.execute()

    def off(self):
        self.off_cmd.execute()


light = Light()
switch = Switch(on_cmd=TurnOnLightCommand(light),
                off_cmd=TurnOffLightCommand(light))
switch.on()  # Включить свет
switch.off() # Выключить свет

Цепочка обязанностей (Chain of Responsibility)

Цепочка обязанностей (Chain of Responsibility)
— это поведенческий паттерн, который позволяет передавать данные последовательно по обработчикам цепочки.
На практике очень часто используется с паттерном проектирования Компоновщик. Т.к. в дереве элементов легко можно выделить цепочку обработчиков.
Также паттерн проектирования python Цепочка обязанностей очень похож на паттерн Декоратор.
Однако, в отличие от декоратора обработчик может прервать цепочку.

Реализация паттерна проектирования Цепочка обязанностей на python

# coding: utf-8

class HttpHandler(object):
    """Абстрактный класс обработчика"""
    def handle(self, code):
        raise NotImplementedError()


class Http404Handler(HttpHandler):
    """Обработчик для кода 404"""
    def handle(self, code):
        if code == 404:
            return 'Страница не найдена'


class Http500Handler(HttpHandler):
    """Обработчик для кода 500"""
    def handle(self, code):
        if code == 500:
            return 'Ошибка сервера'


class Client(object):
    def __init__(self):
        self._handlers = []

    def add_handler(self, h):
        self._handlers.append(h)

    def response(self, code):
        for h in self._handlers:
            msg = h.handle(code)
            if msg:
                print 'Ответ: %s' % msg
                break
        else:
            print 'Код не обработан'


client = Client()
client.add_handler(Http404Handler())
client.add_handler(Http500Handler())
client.response(400)  # Код не обработан
client.response(404)  # Ответ: Страница не найдена
client.response(500) # Ответ: Ошибка сервера

Отличие сортировки списков в python 2 и python 3

Проблема в том, что python 3 отказывается сортировать списки, содержащие значения None!

x = [1, 2, 3, 5555, -1, 0, None, None]
x.sort()

# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: ‘<‘ not supported between instances of ‘NoneType’ and ‘int’

Вариант обхода этой ситуации — это:
x.sort(key=lambda x: x or -1)

Паттерн Прототип (Prototype) на Python

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


# coding: utf-8

import copy

class Prototype(object):
def __init__(self):
self._objects = {}

def register(self, name, obj):
self._objects[name] = obj

def unregister(self, name):
del self._objects[name]

def clone(self, name, attrs):
obj = copy.deepcopy(self._objects[name])
obj.__dict__.update(attrs)
return obj

class Bird(object):
"""Птица"""

prototype = Prototype()
prototype.register('bird', Bird())

owl = prototype.clone('bird', {'name': 'Owl'})
print type(owl), owl.name # Owl

duck = prototype.clone('bird', {'name': 'Duck'})
print type(duck), duck.name # Duck

Паттерн строитель (builder) на python

Строитель (Builder) — паттерн, порождающий объекты.
Отделяет конструирование сложного объекта от его представления,
так что в результате одного и того же процесса конструирования могут получаться разные представления.
От абстрактной фабрики отличается тем, что делает акцент на пошаговом конструировании объекта.
Строитель возвращает объект на последнем шаге, тогда как абстрактная фабрика возвращает объект немедленно.
Строитель часто используется для создания паттерна компоновщик.

Реализация паттерна Строитель на python

# coding: utf-8


class Builder(object):
    def build_body(self):
        raise NotImplementedError()

    def build_lamp(self):
        raise NotImplementedError()

    def build_battery(self):
        raise NotImplementedError()

    def create_flashlight(self):
        raise NotImplementedError()


class Flashlight(object):
    """Карманный фонарик"""
    def __init__(self, body, lamp, battery):
        self._shine = False  # излучать свет
        self._body = body
        self._lamp = lamp
        self._battery = battery

    def on(self):
        self._shine = True

    def off(self):
        self._shine = False

    def __str__(self):
        shine = 'on' if self._shine else 'off'
        return 'Flashlight [%s]' % shine


class Lamp(object):
    """Лампочка"""


class Body(object):
    """Корпус"""


class Battery(object):
    """Батарея"""


class FlashlightBuilder(Builder):
    def build_body(self):
        return Body()

    def build_battery(self):
        return Battery()

    def build_lamp(self):
        return Lamp()

    def create_flashlight(self):
        body = self.build_body()
        lamp = self.build_lamp()
        battery = self.build_battery()
        return Flashlight(body, lamp, battery)


builder = FlashlightBuilder()
flashlight = builder.create_flashlight()
flashlight.on()
print flashlight  # Flashlight [on]

Паттерн абстрактная фабрика на python

Абстрактная фабрика — это порождающий паттерн, который позволяет создавать группы взаимозависимых или связанных объектов, не конкретизируя классы этих объектов.

# coding: utf-8

class AbstractFactory(object):
def create_drink(self):
raise NotImplementedError()

def create_food(self):
raise NotImplementedError()

class Drink(object):
def __init__(self, name):
self._name = name

def __str__(self):
return self._name

class Food(object):
def __init__(self, name):
self._name = name

def __str__(self):
return self._name

class ConcreteFactory1(AbstractFactory):
def create_drink(self):
return Drink('Coca-cola')

def create_food(self):
return Food('Hamburger')

class ConcreteFactory2(AbstractFactory):
def create_drink(self):
return Drink('Pepsi')

def create_food(self):
return Food('Cheeseburger')

def get_factory(ident):
if ident == 0:
return ConcreteFactory1()
elif ident == 1:
return ConcreteFactory2()

factory = get_factory(1)
print factory.create_drink() # Pepsi
print factory.create_food() # Cheeseburger

Паттерн Фабричный метод (Factory Method) на Python

Фабричный метод — это порождающий паттерн проектирования, который позволяет подклассам изменять создаваемый объект, в зависимости от контекста. Объединяя сущности в обобщенную абстракцию.

Реализация паттерна фабричный метод на Python

# coding: utf-8

class Document(object):
    def show(self):
        raise NotImplementedError()


class ODFDocument(Document):
    def show(self):
        print 'Open document format'


class MSOfficeDocument(Document):
    def show(self):
        print 'MS Office document format'


class Application(object):
    def create_document(self, type_):
        # параметризованный фабричный метод `create_document`
        raise NotImplementedError()


class MyApplication(Application):
    def create_document(self, type_):
        if type_ == 'odf':
            return ODFDocument()
        elif type_ == 'doc':
            return MSOfficeDocument()


app = MyApplication()
app.create_document('odf').show()  # Open document format
app.create_document('doc').show() # MS Office document format

Паттерн Заместитель (Proxy) на Python

Заместитель (proxy) — еще один структурный паттерн, схожий с фасадом или адаптером, только у прокси интерфейс полностью повторяет интерфейс замещающего объекта. Используется для отложенных действий над самим объектом, ограничения доступа к объекту, логирования и т.д.

Пример реализации паттерна Заместитель (proxy) на Python.

# coding: utf-8

from functools import partial


class ImageBase(object):
    """Абстрактное изображение"""
    @classmethod
    def create(cls, width, height):
        """Создает изображение"""
        return cls(width, height)

    def draw(self, x, y, color):
        """Рисует точку заданным цветом"""
        raise NotImplementedError()

    def fill(self, color):
        """Заливка цветом"""
        raise NotImplementedError()

    def save(self, filename):
        """Сохраняет изображение в файл"""
        raise NotImplementedError()


class Image(ImageBase):
    """Изображение"""
    def __init__(self, width, height):
        self._width = int(width)
        self._height = int(height)

    def draw(self, x, y, color):
        print 'Рисуем точку; координаты: (%d, %d); цвет: %s' % (x, y, color)

    def fill(self, color):
        print 'Заливка цветом %s' % color

    def save(self, filename):
        print 'Сохраняем изображение в файл %s' % filename


class ImageProxy(ImageBase):
    """
    Заместитель изображения.
    Откладывает выполнение операций над изображением до момента его сохранения.
    """
    def __init__(self, *args, **kwargs):
        self._image = Image(*args, **kwargs)
        self.operations = []

    def draw(self, *args):
        func = partial(self._image.draw, *args)
        self.operations.append(func)

    def fill(self, *args):
        func = partial(self._image.fill, *args)
        self.operations.append(func)

    def save(self, filename):
        # выполняем все операции над изображением
        map(lambda f: f(), self.operations)
        # сохраняем изображение
        self._image.save(filename)


img = ImageProxy(200, 200)
img.fill('gray')
img.draw(0, 0, 'green')
img.draw(0, 1, 'green')
img.draw(1, 0, 'green')
img.draw(1, 1, 'green')
img.save('image.png')

# Заливка цветом gray
# Рисуем точку; координаты: (0, 0); цвет: green
# Рисуем точку; координаты: (0, 1); цвет: green
# Рисуем точку; координаты: (1, 0); цвет: green
# Рисуем точку; координаты: (1, 1); цвет: green
# Сохраняем изображение в файл image.png

Паттерн фасад (facade) python

Фасад — структурный паттерн проектирования, позволяющий дать интерфейс более высокого уровня к сложной системе.
В отличии от адаптера, используется новый интерфейс.
Большой минус в том, что в данной концепции, фасад может стать godlike, связанным со всей системой.
Иногда фасад превращают в синглтон, т.к. обычно нужен всего 1 фасад.

реализация паттерна
[сode lang=»python»]
# coding: utf-8

class Paper(object):
«»»Бумага»»»
def __init__(self, count):
self._count = count

def get_count(self):
return self._count

def draw(self, text):
if self._count > 0:
self._count -= 1
print text

class Printer(object):
«»»Принтер»»»
def error(self, msg):
print ‘Ошибка: %s’ % msg

def print_(self, paper, text):
if paper.get_count() > 0:
paper.draw(text)
else:
self.error(‘Бумага закончилась’)

class Facade(object):
def __init__(self):
self._printer = Printer()
self._paper = Paper(1)

def write(self, text):
self._printer.print_(self._paper, text)

f = Facade()
f.write(‘Hello world!’) # Hello world!
f.write(‘Hello world!’) # Ошибка: Бумага закончилась
[/code]

паттерн Декоратор (decorator) python

Паттерн Декоратор(decorator) еще один структурный паттерн, который позовляет наделять объекты новыми свойствами и по сути является альтернативой наследованию. В отличии от адаптера не меняет интерфейс!

# coding: utf-8

class Man(object):
    """Человек"""
    def __init__(self, name):
        self._name = name

    def say(self):
        print 'Привет! Меня зовут %s!' % self._name


class Jetpack(object):
    """Реактивный ранец"""
    def __init__(self, man):
        self._man = man

    def __getattr__(self, item):
        return getattr(self._man, item)

    def fly(self):
        # расширяем функциональность объекта добавляя возможность летать
        print '%s летит на реактивном ранце!' % self._man._name


man = Man('Александр')

man_jetpack = Jetpack(man)
man_jetpack.say()  # Привет! Меня зовут Александр!
man_jetpack.fly()  # Виктор летит на реактивном ранце!