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.
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.
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-, +, |.
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.|*||/
/||*+- - - - - -+*||/
/|+- - - - - - - - - -+|/
/+- - - - - - - - - - - -+/
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
Recommended Posts