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

Введение

Примеры

  • 0

    Стратегия

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

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

    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 .

  • 1

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

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

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

    1. The pattern name является дескриптором мы можем использовать , чтобы описать проблему проектирования, ее решения, а также последствия в два слова.
    2. The problem описывает , когда применить шаблон.
    3. The solution описывает элементы, составляющие конструкцию, их отношения, обязанности и сотрудничество.
    4. The consequences результаты и компромиссы применения шаблона.

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

    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 в зависимости от выбора пользователя обеспечивает.

  • 0

    полномочие

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

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

    Определение прокси: (оно гарантирует, что только пользователи, которые на самом деле могут видеть резервирования, будут иметь возможность потребителю 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 ) свободен от разрешений , связанных логики , а также

    ПРЕДОСТЕРЕЖЕНИЯ

    • Интерфейс прокси всегда точно такой же, как объект, который он скрывает, так что пользователь, который использует сервис, заключенный в прокси, даже не знал о наличии прокси.

Синтаксис

Параметры

Примечания