[PYTHON] Modèle de conception #Decorator

J'ai pratiqué les modèles de conception afin de pouvoir écrire du code conscient du design. D'autres modèles de conception seront publiés fréquemment.

Préface

L'objectif principal est de comprendre quand, quoi et comment utiliser les modèles de conception. (Je suis nouveau en Java ou dans un langage à typage statique, et je n'ai pas une longue histoire de python, donc je pense qu'il y a des choses qui ne ressemblent pas à Pythonista. Si vous avez des suggestions, apprenez-moi.)

Cette fois, le décorateur de motifs était lié à la structure.

Qu'est-ce que le décorateur

En recouvrant un objet existant avec un nouvel objet Decorator tout en conservant une interface transparente (API), des fonctions peuvent être ajoutées ou réécrites de l'extérieur sans toucher directement le contenu des fonctions et classes existantes. Il est également utilisé comme alternative à l'héritage de classe lors de l'extension d'une classe existante.

L'exemple de programme créé ici consiste à afficher un cadre décoratif autour de la chaîne de caractères. Le cadre décoratif ici est écrit avec les caractères-, +, |.

Diagramme de classe global

Decorator

display.py


from abc import ABCMeta, abstractmethod


class Display(metaclass=ABCMeta):

    @abstractmethod
    def get_columns(self):
        pass

    @abstractmethod
    def get_rows(self):
        pass

    @abstractmethod
    def get_row_text(self):
        pass

    def show(self):
        for i in range(self.get_rows()):
            print(self.get_row_text(i))

La classe Display est une classe abstraite qui affiche une chaîne multiligne.

Puisque get_columns, get_rows et get_row_text sont des méthodes abstraites, seule la déclaration est laissée à la sous-classe. Chaque rôle est get_columns est le nombre de caractères horizontaux, get_rows est le nombre de lignes verticales et get_row_text est une méthode pour obtenir la chaîne de caractères de la ligne spécifiée.

Le spectacle est un modèle de méthode de modèle qui utilise les méthodes abstraites get_rows et get_row_text. C'est une méthode pour obtenir la chaîne de caractères à afficher par get_rows et get_row_text et afficher toutes les lignes de la boucle for.

string_display.py



from display import Display


class StringDisplay(Display):

    def __init__(self, string):
        self.__string = string

    def get_columns(self):
        return len(self.__string)

    def get_rows(self):
        return 1

    def get_row_text(self, row):
        if row == 0:
            return self.__string
        else:
            return None

La classe StringDisplay est une classe qui affiche une seule ligne de texte et est une sous-classe de la classe Display. Il implémente la méthode abstraite déclarée dans la classe Display. Le champ de chaîne contient la chaîne à afficher. La classe StringDisplay n'affiche qu'une seule ligne de contenu de champ de chaîne, donc get_columns renvoie la longueur de la chaîne et get_rows renvoie 1. get_row_text renvoie un champ de chaîne uniquement lorsqu'il prend la valeur de la ligne 0.

border.py


from abc import ABCMeta
from display import Display


class Border(Display):

    __metaclass__ = ABCMeta

    def _border(self, display):
        self._display = display

La classe Border est une classe abstraite qui représente un "cadre décoratif". Cependant, il est défini comme une sous-classe de la classe Display qui affiche des chaînes. En d'autres termes, par héritage ** le cadre a la même méthode que le contenu **. La classe Border hérite des méthodes get_columns, get_rows, get_row_text et show.

side_border.py


from border import Border


class SideBorder(Border):

    def __init__(self, display, ch):
        self.display = display
        self.__border_char = ch

    def get_columns(self):
        return 1 + self.display.get_columns() + 1

    def get_rows(self):
        return self.display.get_rows()

    def get_row_text(self, row):
        return self.__border_char + \
            self.display.get_row_text(row) + \
            self.__border_char

La classe SideBorder est une sorte de cadre décoratif en béton et est une sous-classe de la classe Border. La classe SideBorder décore les côtés gauche et droit de la chaîne de caractères avec des caractères fixes (borderChar). Et toutes les méthodes abstraites déclarées dans la superclasse sont implémentées ici.

get_columns est une méthode pour obtenir le nombre de caractères à côté des caractères affichés. Le nombre de caractères est le nombre de caractères dans le «contenu» qui est enroulé autour de ce cadre décoratif, plus les caractères décoratifs gauche et droit.

Étant donné que la classe SideBorder ne modifie pas la direction verticale, display.get_rows est la valeur de retour de la méthode get_rows.

La méthode get_row_text récupère la chaîne de la ligne spécifiée par l'argument. La valeur de retour est display.get_row_text (ligne) avec le caractère décoratif bodrder_char ajouté des deux côtés de la chaîne de contenu.

full_border.py


from border import Border


class FullBorder(Border):

    def __init__(self, display):
        self.display = display

    def get_columns(self):
        return 1 + self.display.get_columns() + 1

    def get_rows(self):
        return 1 + self.display.get_rows() + 1

    def get_row_text(self, row):
        if row == 0:
            return '+' + self._make_line('-', self.display.get_columns()) + '+'
        elif row == self.display.get_rows() + 1:
            return '+' + self._make_line('-', self.display.get_columns()) + '+'
        else:
            return '|' + self.display.get_row_text(row - 1) + '|'

    def _make_line(self, ch, count):
        buf = []
        for i in range(0, count):
            buf.append(ch)
        return ' '.join(buf)

La classe FullBorder, comme la classe SideBorder, est l'une des sous-classes Border. La classe FullBorder est décorée en haut, en bas, à gauche et à droite.

La méthode make_line est une méthode auxiliaire qui crée une chaîne de caractères spécifiés consécutifs.

main.py


from string_display import StringDisplay
from side_border import SideBorder
from full_border import FullBorder


def main():
    b1 = StringDisplay('Hello, world')
    b2 = SideBorder(b1, '#')
    b3 = FullBorder(b2)
    b4 = SideBorder(
        FullBorder(
            FullBorder(
                SideBorder(
                    FullBorder(
                        StringDisplay('Bonjour.')
                    ), '*'
                )
            )
        ), '/'
    )

    b1.show()
    b2.show()
    b3.show()
    b4.show()

if __name__ == "__main__":
    main()

Résultat de l'exécution (bien que la forme soit déformée ...)

Hello, world
#Hello, world#
+- - - - - - - - - - - - - -+
|#Hello, world#|
+- - - - - - - - - - - - - -+
/+- - - - - - - - - - - -+/
/|+- - - - - - - - - -+|/
/||*+- - - - - -+*||/
/||*|Bonjour.|*||/
/||*+- - - - - -+*||/
/|+- - - - - - - - - -+|/
/+- - - - - - - - - - - -+/

Résumé

Dans le modèle Decorator, le cadre décoratif et le contenu sont assimilés.

Dans l'exemple de programme, l'identification est exprimée où la classe Border qui représente le cadre décoratif est une sous-classe de la classe Display qui représente le contenu. En d'autres termes, la classe Border (sous-classes de la classe Border) a la même interface que la classe Display qui représente le contenu.

Même si vous utilisez un cadre pour envelopper le contenu, l'interface n'est pas masquée, donc les méthodes get_columns, get_rows, get_row_text, show peuvent être vues à partir d'autres classes. C'est ce que l'interface est appelée «transparente».

Plus vous enveloppez le motif Decorator, plus il ajoutera de fonctionnalités. ** J'ai pu ajouter des fonctionnalités sans changer ce qui est emballé. ** **

Python a des décorateurs en premier lieu

référence

Recommended Posts

Modèle de conception #Decorator
Modèle de conception #Builder
Modèle de conception #Adapter
Modèle de conception #Observer
Modèle de conception #Facade
Modèle de conception #Strategy
Modèle de conception #Singleton
Modèle de conception #Proxy
Apprenez le modèle de conception "Décorateur" avec Python
Design Pattern #Factory, méthode
Modèle de décorateur en Java
Design Pattern #Template, méthode
Décorateur 1
Décorateur 2
Modèle de conception Oreore: variable glocale
Décorateur
Décorateur
Python Design Pattern - Méthode de modèle
[Gang of Four] Apprentissage des modèles de conception
Résumé du modèle de conception Java GoF
Apprenez le modèle de conception "Prototype" avec Python
Apprenez le modèle de conception "Builder" avec Python
[Gang of Four] Apprentissage des modèles de conception --Singleton
[Gang of Four] Apprentissage des modèles de conception - Visiteur
Modèle de conception-Adaptateur
[Gang of Four] Apprentissage des modèles de conception - Médiateur
Apprenez le modèle de conception "Flyweight" en Python
Apprenez le modèle de conception "Observer" en Python
Apprenez le modèle de conception "Memento" avec Python
Apprenez le modèle de conception "Proxy" en Python
Apprenez le modèle de conception "Commande" en Python
[Gang of Four] Apprentissage des modèles de conception - Itérateur
Décorateur MyHDL
Modèle de conception du GoF à partir du problème 2. Structure
Apprenez le modèle de conception "Visiteur" avec Python
Apprenez le modèle de conception "Bridge" avec Python
Apprenez le modèle de conception "Mediator" avec Python
Modèle de conception-Itérateur
[Gang of Four] Apprentissage des modèles de conception - Façade
[Gang of Four] Apprentissage des modèles de conception - Composite
[Gang of Four] Apprentissage des modèles de conception - Prototype
Modèle de conception du GoF à partir du problème 1. Génération
Apprenez le modèle de conception "Iterator" avec Python
[Gang of Four] Apprentissage des modèles de conception --Mémento
[Gang of Four] Apprentissage des modèles de conception - État
[Gang of Four] Apprentissage des modèles de conception - Interprétation
[Gang of Four] Apprentissage des modèles de conception - Constructeur
Apprenez le modèle de conception «Stratégie» avec Python
[Gang of Four] Apprentissage des modèles de conception - Pont
Apprenez le modèle de conception "Composite" avec Python
Apprenez le modèle de conception "Singleton" avec Python
Apprenez le modèle de conception "État" en Python
Apprenez le modèle de conception "Adapter" avec Python
[Gang of Four] Apprentissage des modèles de conception - Proxy
[Gang of Four] Apprentissage des modèles de conception - Stratégie
[Gang of Four] Apprentissage des modèles de conception - Adaptateur
Apprenez le modèle de conception "Façade" avec Python
[Gang of Four] Apprentissage des modèles de conception --Observer
[Gang of Four] Apprentissage des modèles de conception - Commande
Modèle de conception GoF à partir du problème 3. Comportement
[Gang of Four] Apprentissage des modèles de conception - Poids du vol