Python Language Procuration


Exemple

L'objet proxy est souvent utilisé pour garantir un accès sécurisé à un autre objet, quelle logique métier interne nous ne voulons pas polluer avec les exigences de sécurité.

Supposons que nous souhaitons garantir que seul l'utilisateur des autorisations spécifiques puisse accéder aux ressources.

Définition du proxy: (il garantit que seuls les utilisateurs capables de voir les réservations pourront utiliser le service reservation_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)

AVANTAGES
  • nous évitons tout changement dans ReservationService lorsque les restrictions d'accès sont modifiées.
  • Nous ne date_from pas les données liées à l'entreprise ( date_from , date_to , reservations_count ) avec les concepts non liés au domaine (autorisations utilisateur) en service.
  • Consumer ( StatsService ) est également exempt de logique liée aux autorisations

CAVEATS
  • L'interface proxy est toujours exactement identique à l'objet qu'elle cache, de sorte que l'utilisateur qui consomme le service encapsulé par un proxy n'était même pas au courant de la présence de proxy.