Документация по Python

Шаблоны проектирования

В: Документация по Python

Введение

Примеры

Стратегия

Этот шаблон дизайна называется Стратегическим шаблоном. Он используется для определения семейства алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Шаблон разработки стратегии позволяет алгоритму варьироваться независимо от клиентов, которые его используют.

Например, животные могут «гулять» разными способами. Прогулку можно считать стратегией, которую реализуют разные виды животных:

from types import MethodType


class Animal(object):

    def __init__(self, *args, **kwargs):
        self.name = kwargs.pop('name', None) or 'Animal'
        if kwargs.get('walk', None):
            self.walk = MethodType(kwargs.pop('walk'), self)

    def walk(self):
        """
        Cause animal instance to walk

        Walking funcionallity is a strategy, and is intended to
        be implemented separately by different types of animals.
        """
        message = '{} should implement a walk method'.format(
            self.__class__.__name__)
        raise NotImplementedError(message)


# Here are some different walking algorithms that can be used with Animal
def snake_walk(self):
    print('I am slithering side to side because I am a {}.'.format(self.name))

def four_legged_animal_walk(self):
    print('I am using all four of my legs to walk because I am a(n) {}.'.format(
        self.name))

def two_legged_animal_walk(self):
    print('I am standing up on my two legs to walk because I am a {}.'.format(
        self.name))

 

Запуск этого примера приведет к следующему выводу:

 generic_animal = Animal()
king_cobra = Animal(name='King Cobra', walk=snake_walk)
elephant = Animal(name='Elephant', walk=four_legged_animal_walk)
kangaroo = Animal(name='Kangaroo', walk=two_legged_animal_walk)

kangaroo.walk()
elephant.walk()
king_cobra.walk()
# This one will Raise a NotImplementedError to let the programmer
# know that the walk method is intended to be used as a strategy.
generic_animal.walk()

    # OUTPUT:
    #
    # I am standing up on my two legs to walk because I am a Kangaroo.
    # I am using all four of my legs to walk because I am a(n) Elephant.
    # I am slithering side to side because I am a King Cobra.
    # Traceback (most recent call last):
    #   File "./strategy.py", line 56, in <module>
    #     generic_animal.walk()
    #   File "./strategy.py", line 30, in walk
    #     raise NotImplementedError(message)
    # NotImplementedError: Animal should implement a walk method 

 

Обратите внимание, что в таких языках, как C ++ или Java, этот шаблон реализован с использованием абстрактного класса или интерфейса для определения стратегии. В Python это имеет смысл только определить некоторые функции внешне , которые могут быть добавлены динамически в классе с использованием types.MethodType .

Введение в шаблоны проектирования и Singleton Pattern

Шаблоны обеспечивают решение commonly occurring problems в разработке программного обеспечения. Образцы дизайна впервые были введены GoF(Gang of Four) , где они описаны общие закономерности как проблемы , которые возникают снова и снова , и решение этих проблем.

Шаблоны проектирования имеют четыре основных элемента:

Преимущества дизайна выкройки:

  1. Они могут быть использованы в нескольких проектах.
  2. Архитектурный уровень проблем может быть решен
  3. Они проверены временем и хорошо себя зарекомендовали, что является опытом разработчиков и архитекторов.
  4. У них есть надежность и зависимость

Шаблоны проектирования можно разделить на три категории:

  1. Творческий Образец
  2. Структурная картина
  3. Поведенческая картина

Creational Pattern - Они обеспокоены тем , как объект может быть создан и они изолируют детали создания объекта.

Structural Pattern - Они разрабатывают структуру классов и объектов таким образом, чтобы они могли составить для достижения больших результатов.

Behavioral Pattern - Они связаны с взаимодействием между объектами и ответственности объектов.

Singleton Pattern:

Это тип creational pattern , который обеспечивает механизм , чтобы иметь только один и один объект данного типа и обеспечивает глобальную точку доступа.

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

Реализация

Мы можем реализовать шаблон Singleton в Python, создав только один экземпляр класса Singleton и снова предоставив тот же объект.

 class Singleton(object):
    def __new__(cls):
        # hasattr method checks if the class object an instance property or not.
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance

s = Singleton()
print("Object created", s)

s1 = Singleton()
print("Object2 created", s1)

 

Выход:

('Object created', <__main__.Singleton object at 0x10a7cc310>)
('Object2 created', <__main__.Singleton object at 0x10a7cc310>)

 

Обратите внимание, что в таких языках, как C ++ или Java, этот шаблон реализуется путем обеспечения приватности конструктора и создания статического метода, выполняющего инициализацию объекта. Таким образом, один объект создается при первом вызове, а класс возвращает тот же объект после этого. Но в Python у нас нет никакого способа создавать частные конструкторы.

Фабричный образец

Завод шаблон также Creational pattern.Термин factory означает , что класс отвечает за создание объектов других типов. Существует класс, который действует как фабрика, с которой связаны объекты и методы. Клиент создает объект, вызывая методы с определенными параметрами, а фабрика создает объект нужного типа и возвращает его клиенту.

 from abc import ABCMeta, abstractmethod

class Music():
    __metaclass__ = ABCMeta
    @abstractmethod
    def do_play(self):
        pass

class Mp3(Music):
    def do_play(self):
        print("Playing .mp3 music!")

class Ogg(Music):
    def do_play(self):
        print("Playing .ogg music!")

class MusicFactory(object):
    def play_sound(self, object_type):
        return eval(object_type)().do_play()

if __name__ == "__main__":
    mf = MusicFactory()
    music = input("Which music you want to play Mp3 or Ogg")
    mf.play_sound(music)

 

Выход:

 Which music you want to play Mp3 or Ogg"Ogg"
Playing .ogg music!

 

MusicFactory класс завода здесь создает либо объект типа Mp3 или Ogg в зависимости от выбора пользователя обеспечивает.

полномочие

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

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

Определение прокси: (оно гарантирует, что только пользователи, которые на самом деле могут видеть резервирования, будут иметь возможность потребителю booking_service)

from datetime import date
from operator import attrgetter

class Proxy:
    def __init__(self, current_user, reservation_service):
        self.current_user = current_user
        self.reservation_service = reservation_service

    def highest_total_price_reservations(self, date_from, date_to, reservations_count):
        if self.current_user.can_see_reservations:
            return self.reservation_service.highest_total_price_reservations(
                date_from,
                date_to,
                reservations_count
              )
        else:
            return []

#Models and ReservationService:

class Reservation:
    def __init__(self, date, total_price):
        self.date = date
        self.total_price = total_price

class ReservationService:
    def highest_total_price_reservations(self, date_from, date_to, reservations_count):
        # normally it would be read from database/external service
        reservations = [
            Reservation(date(2014, 5, 15), 100),
            Reservation(date(2017, 5, 15), 10),
            Reservation(date(2017, 1, 15), 50)
        ]

        filtered_reservations = [r for r in reservations if (date_from <= r.date <= date_to)]

        sorted_reservations = sorted(filtered_reservations, key=attrgetter('total_price'), reverse=True)

        return sorted_reservations[0:reservations_count]


class User:
    def __init__(self, can_see_reservations, name):
        self.can_see_reservations = can_see_reservations
        self.name = name

#Consumer service:

class StatsService:
    def __init__(self, reservation_service):
        self.reservation_service = reservation_service

    def year_top_100_reservations_average_total_price(self, year):
        reservations = self.reservation_service.highest_total_price_reservations(
            date(year, 1, 1),
            date(year, 12, 31),
            1
        )

        if len(reservations) > 0:
            total = sum(r.total_price for r in reservations)

            return total / len(reservations)
        else:
            return 0

#Test:
def test(user, year):
    reservations_service = Proxy(user, ReservationService())
    stats_service = StatsService(reservations_service)
    average_price = stats_service.year_top_100_reservations_average_total_price(year)
    print("{0} will see: {1}".format(user.name, average_price))

test(User(True, "John the Admin"), 2017)
test(User(False, "Guest"),         2017)

 

ВЫГОДЫ

  • мы избежать каких - либо изменений в ReservationService когда ограничение доступа изменены.
  • мы не смешивая данные , относящиеся к бизнес ( date_from , date_to , reservations_count ) с доменными несвязанными понятиями (права пользователя) в процессе эксплуатации.
  • Потребитель ( StatsService ) свободен от разрешений , связанных логики , а также  ПРЕДОСТЕРЕЖЕНИЯ
  • Интерфейс прокси всегда точно такой же, как объект, который он скрывает, так что пользователь, который использует сервис, заключенный в прокси, даже не знал о наличии прокси.

Синтаксис

Параметры

Примечания

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.