Le modèle Decorator fait référence à des modèles de conception structurelle.
Le décorateur est utilisé comme alternative à l’héritage pour étendre les fonctionnalités des classes.
Il existe une tâche consistant à étendre les fonctionnalités de l’application en fonction du type de produit. Le client a besoin de trois types de produits : Basique, Professionnel, Ultime.
De base– compte le nombre de caractères, Professionnel – capacités Basic + imprime le texte en majuscules, Ultimate – Basic + Professional + imprime le texte disant ULTIMATE.
Nous l’implémentons en utilisant l’héritage :
protocol Feature {
func textOperation(text: String)
}
class BasicVersionFeature: Feature {
func textOperation(text: String) {
print("\(text.count)")
}
}
class ProfessionalVersionFeature: BasicVersionFeature {
override func textOperation(text: String) {
super.textOperation(text: text)
print("\(text.uppercased())")
}
}
class UltimateVersionFeature: ProfessionalVersionFeature {
override func textOperation(text: String) {
super.textOperation(text: text)
print("ULTIMATE: \(text)")
}
}
let textToFormat = "Hello Decorator"
let basicProduct = BasicVersionFeature()
basicProduct.textOperation(text: textToFormat)
let professionalProduct = ProfessionalVersionFeature()
professionalProduct.textOperation(text: textToFormat)
let ultimateProduct = UltimateVersionFeature()
ultimateProduct.textOperation(text: textToFormat)
Il est désormais nécessaire de mettre en œuvre le produit « Ultimate Light » – 8211 ; Basic + Ultimate mais sans les capacités de la version Professionnelle. Le premier OH! arrive, parce que… vous devrez créer une classe distincte pour une tâche aussi simple et dupliquer le code.
Continuons l’implémentation en utilisant l’héritage :
protocol Feature {
func textOperation(text: String)
}
class BasicVersionFeature: Feature {
func textOperation(text: String) {
print("\(text.count)")
}
}
class ProfessionalVersionFeature: BasicVersionFeature {
override func textOperation(text: String) {
super.textOperation(text: text)
print("\(text.uppercased())")
}
}
class UltimateVersionFeature: ProfessionalVersionFeature {
override func textOperation(text: String) {
super.textOperation(text: text)
print("ULTIMATE: \(text)")
}
}
class UltimateLightVersionFeature: BasicVersionFeature {
override func textOperation(text: String) {
super.textOperation(text: text)
print("ULTIMATE: \(text)")
}
}
let textToFormat = "Hello Decorator"
let basicProduct = BasicVersionFeature()
basicProduct.textOperation(text: textToFormat)
let professionalProduct = ProfessionalVersionFeature()
professionalProduct.textOperation(text: textToFormat)
let ultimateProduct = UltimateVersionFeature()
ultimateProduct.textOperation(text: textToFormat)
let ultimateLightProduct = UltimateLightVersionFeature()
ultimateLightProduct.textOperation(text: textToFormat)
L’exemple peut être développé davantage pour plus de clarté, mais même maintenant, la complexité de la prise en charge d’un système basé sur une base d’héritage est visible – encombrant et manque de flexibilité.
Un décorateur est un ensemble de protocoles décrivant la fonctionnalité, une classe abstraite contenant une référence à une instance concrète enfant de la classe décorateur qui étend la fonctionnalité.
Réécrivons l’exemple ci-dessus en utilisant le modèle :
protocol Feature {
func textOperation(text: String)
}
class FeatureDecorator: Feature {
private var feature: Feature?
init(feature: Feature? = nil) {
self.feature = feature
}
func textOperation(text: String) {
feature?.textOperation(text: text)
}
}
class BasicVersionFeature: FeatureDecorator {
override func textOperation(text: String) {
super.textOperation(text: text)
print("\(text.count)")
}
}
class ProfessionalVersionFeature: FeatureDecorator {
override func textOperation(text: String) {
super.textOperation(text: text)
print("\(text.uppercased())")
}
}
class UltimateVersionFeature: FeatureDecorator {
override func textOperation(text: String) {
super.textOperation(text: text)
print("ULTIMATE: \(text)")
}
}
let textToFormat = "Hello Decorator"
let basicProduct = BasicVersionFeature(feature: UltimateVersionFeature())
basicProduct.textOperation(text: textToFormat)
let professionalProduct = ProfessionalVersionFeature(feature: UltimateVersionFeature())
professionalProduct.textOperation(text: textToFormat)
let ultimateProduct = BasicVersionFeature(feature: UltimateVersionFeature(feature: ProfessionalVersionFeature()))
ultimateProduct.textOperation(text: textToFormat)
let ultimateLightProduct = BasicVersionFeature(feature: UltimateVersionFeature())
ultimateLightProduct.textOperation(text: textToFormat)
Nous pouvons désormais créer des variantes de n’importe quel type de produit – il suffit d’initialiser les types combinés au stade du lancement de l’application ; l’exemple ci-dessous est la création de la version Ultimate + Professional :
ultimateProfessionalProduct.textOperation(text: textToFormat)
Sources
https://refactoring.guru/ru/design-patterns/decorator
Code source
https://gitlab.com/demensdeum/patterns