Comprendre le «modèle de décorateur» avec un exemple concret

167

J'étudiais le modèle de décorateur tel que documenté dans GOF .

S'il vous plaît, aidez-moi à comprendre le modèle de décorateur . Quelqu'un pourrait-il donner un exemple de cas d'utilisation où cela est utile dans le monde réel?

odiseh
la source
8
Vous pouvez trouver ici quelques exemples du monde réel dans l'API Java: stackoverflow.com/questions/1673841/…
BalusC
Un article qui montre les avantages du modèle de décoration
nbilal

Réponses:

226

Le modèle de décorateur atteint un seul objectif d'ajouter dynamiquement des responsabilités à n'importe quel objet.

Prenons le cas d'une pizzeria. Dans la pizzeria, ils vendront quelques variétés de pizzas et ils fourniront également des garnitures dans le menu. Imaginez maintenant une situation dans laquelle si la pizzeria doit fournir des prix pour chaque combinaison de pizza et de garniture. Même s'il y a quatre pizzas de base et 8 garnitures différentes, l'application deviendrait folle en conservant toutes ces combinaisons concrètes de pizzas et de garnitures.

Voici le motif du décorateur.

Selon le modèle du décorateur, vous mettrez en œuvre des garnitures au fur et à mesure que les décorateurs et les pizzas seront décorées par les décorateurs de ces garnitures. Pratiquement chaque client voudrait des garnitures de son désir et le montant final de la facture sera composé des pizzas de base et des garnitures commandées en plus. Chaque décorateur de garniture connaîtrait les pizzas qu'il décore et son prix. La méthode GetPrice () de l'objet Topping renverrait le prix cumulé de la pizza et de la garniture.

ÉDITER

Voici un exemple de code d'explication ci-dessus.

public abstract class BasePizza
{
    protected double myPrice;

    public virtual double GetPrice()
    {
        return this.myPrice;
    }
}

public abstract class ToppingsDecorator : BasePizza
{
    protected BasePizza pizza;
    public ToppingsDecorator(BasePizza pizzaToDecorate)
    {
        this.pizza = pizzaToDecorate;
    }

    public override double GetPrice()
    {
        return (this.pizza.GetPrice() + this.myPrice);
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //Client-code
        Margherita pizza = new Margherita();
        Console.WriteLine("Plain Margherita: " + pizza.GetPrice().ToString());

        ExtraCheeseTopping moreCheese = new ExtraCheeseTopping(pizza);
        ExtraCheeseTopping someMoreCheese = new ExtraCheeseTopping(moreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese: " + someMoreCheese.GetPrice().ToString());

        MushroomTopping moreMushroom = new MushroomTopping(someMoreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom: " + moreMushroom.GetPrice().ToString());

        JalapenoTopping moreJalapeno = new JalapenoTopping(moreMushroom);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom with Jalapeno: " + moreJalapeno.GetPrice().ToString());

        Console.ReadLine();
    }
}

public class Margherita : BasePizza
{
    public Margherita()
    {
        this.myPrice = 6.99;
    }
}

public class Gourmet : BasePizza
{
    public Gourmet()
    {
        this.myPrice = 7.49;
    }
}

public class ExtraCheeseTopping : ToppingsDecorator
{
    public ExtraCheeseTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 0.99;
    }
}

public class MushroomTopping : ToppingsDecorator
{
    public MushroomTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}

public class JalapenoTopping : ToppingsDecorator
{
    public JalapenoTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}
. __curious_geek
la source
104
Je n'aime pas du tout ce modèle. C'est peut-être l'exemple cependant. Le principal problème que j'ai avec cela en termes de OOD est qu'une garniture n'est pas une pizza . Demander la garniture pour le prix de la pizza à laquelle elle est appliquée ne me convient tout simplement pas. C'est un exemple très réfléchi et détaillé, donc je ne veux pas vous frapper pour cela.
Tom W
39
@TomW Je pense qu'une partie du problème est la dénomination. Toutes les classes "Topping" doivent être appelées "PizzaWith <Topping>". Par exemple, "PizzaWithMushrooms".
Josh Noe
2
À mon avis, les décorateurs sont mieux utilisés aussi catégoriquement que possible. J'entends par là le moins possible de "décorateurs enveloppant des décorateurs". Alors peut-être que cet exemple n'est pas le plus approprié. Mais c'est assez complet, ce qui est bien.
thekingoftruth
17
D'un autre point de vue, ce n'est même pas proche du «monde réel». Dans le monde réel, vous ne devez pas recompiler chaque fois que vous devez ajouter une nouvelle garniture dans le menu (ou modifier le prix). Les garnitures sont (généralement) stockées dans la base de données et rendent ainsi l'exemple ci-dessus inutile.
Stelios Adamantidis
4
^ Ceci. Je pense que c'est ce qui m'a dérangé tout au long de l'étude de ce modèle. Si j'étais une société de logiciels et que j'écrivais un logiciel de pizzeria, je ne voudrais pas avoir à recompiler et à renvoyer à chaque fois. Je voudrais ajouter une ligne dans une table dans le backend ou quelque chose qui répondrait facilement à leurs besoins. Bien dit, @Stelios Adamantidis. Je suppose que la plus grande force des modèles serait alors de modifier les classes tierces.
Canucklesandwich
33

Il s'agit d'un exemple simple d'ajout dynamique d'un nouveau comportement à un objet existant ou au modèle Decorator. En raison de la nature des langages dynamiques tels que Javascript, ce modèle devient une partie du langage lui-même.

// Person object that we will be decorating with logging capability
var person = {
  name: "Foo",
  city: "Bar"
};

// Function that serves as a decorator and dynamically adds the log method to a given object
function MakeLoggable(object) {
  object.log = function(property) {
    console.log(this[property]);
  }
}

// Person is given the dynamic responsibility here
MakeLoggable(person);

// Using the newly added functionality
person.log('name');

Anurag
la source
Simple et précis! Excellent exemple!
nagendra547
1
Je ne pense pas que le concept de Decorator Pattern soit applicable ici. En fait, ce n'est pas du tout un modèle !. Oui, vous ajoutez une nouvelle méthode au moment de l'exécution. Et probablement à l'intérieur d'un switchou d'un simple if, vous pourrez affirmer qu'il s'agit d'un excellent exemple d'ajout dynamique de comportement à une classe.Mais, nous avons besoin d'au moins deux classes pour définir un décorateur et des objets décorés dans ce modèle.
Iman
1
@Zich Je comprends qu'il n'y a pas de décorateur dans mon exemple mais c'est facilement corrigé en ajoutant une fonction qui sert de décorateur. Mais il y a un objet décoré dans mon exemple. Le modèle indique-t-il quelque part que vous avez besoin de deux classes spécifiquement?
Anurag
18

Il convient de noter que le modèle d'E / S Java est basé sur le modèle de décorateur. La superposition de ce lecteur au-dessus de ce lecteur au-dessus de ... est un exemple vraiment réel de décorateur.

Frankc
la source
Existe-t-il d'autres exemples dans de vraies API publiques? C'est le seul que je connaisse.
Josiah Yoder
Il semble que toutes les fonctions de wrapper dans la nature ont une sorte de modèle de décorateur intégré, est-ce que je pense que c'est?
Harvey Lin
Bon exemple !!
nagendra547
8

Exemple - Scénario - Disons que vous écrivez un module de chiffrement. Ce cryptage peut crypter le fichier clair à l'aide de la norme de cryptage DES - Data. De même, dans un système, vous pouvez avoir le cryptage en tant que norme de cryptage AES - Advance. En outre, vous pouvez avoir la combinaison de cryptage - d'abord DES, puis AES. Ou vous pouvez avoir d'abord AES, puis DES.

Discussion - Comment allez-vous gérer cette situation? Vous ne pouvez pas continuer à créer l'objet de telles combinaisons - par exemple - AES et DES - total de 4 combinaisons. Ainsi, vous devez avoir 4 objets individuels. Cela deviendra complexe à mesure que le type de cryptage augmentera.

Solution - Continuez à construire la pile - des combinaisons en fonction des besoins - au moment de l'exécution. Un autre avantage de cette approche par pile est que vous pouvez la dérouler facilement.

Voici la solution - en C ++.

Tout d'abord, vous avez besoin d'une classe de base - une unité fondamentale de la pile. Vous pouvez penser comme la base de la pile. Dans cet exemple, il s'agit d'un fichier clair. Suivons toujours le polymorphisme. Faites d'abord une classe d'interface de cette unité fondamentale. De cette façon, vous pouvez l'implémenter comme vous le souhaitez. De plus, vous n'avez pas besoin de penser à la dépendance tout en incluant cette unité fondamentale.

Voici la classe d'interface -

class IclearData
{
public:

    virtual std::string getData() = 0;
    virtual ~IclearData() = 0;
};

IclearData::~IclearData()
{
    std::cout<<"Destructor called of IclearData"<<std::endl;
}

Maintenant, implémentez cette classe d'interface -

class clearData:public IclearData
{
private:

    std::string m_data;

    clearData();

    void setData(std::string data)
        {
            m_data = data;
        }

public:

    std::string getData()
    {
        return m_data;
    }

    clearData(std::string data)
    {
        setData(data);
    }

    ~clearData()
    {
        std::cout<<"Destructor of clear Data Invoked"<<std::endl;
    }

};

Maintenant, créons une classe abstraite de décorateur - qui peut être étendue pour créer n'importe quel type de saveurs - ici, la saveur est le type de cryptage. Cette classe abstraite de décorateur est liée à la classe de base. Ainsi, le décorateur "est une" sorte de classe d'interface. Ainsi, vous devez utiliser l'héritage.

class encryptionDecorator: public IclearData
{

protected:
    IclearData *p_mclearData;

    encryptionDecorator()
    {
      std::cout<<"Encryption Decorator Abstract class called"<<std::endl;
    }

public:

    std::string getData()
    {
        return p_mclearData->getData();
    }

    encryptionDecorator(IclearData *clearData)
    {
        p_mclearData = clearData;
    }

    virtual std::string showDecryptedData() = 0;

    virtual ~encryptionDecorator() = 0;

};

encryptionDecorator::~encryptionDecorator()
{
    std::cout<<"Encryption Decorator Destructor called"<<std::endl;
}

Maintenant, faisons une classe de décorateur concrète - Type de chiffrement - AES -

const std::string aesEncrypt = "AES Encrypted ";

class aes: public encryptionDecorator
{

private:

    std::string m_aesData;

    aes();

public:

    aes(IclearData *pClearData): m_aesData(aesEncrypt)
    {
        p_mclearData = pClearData;
        m_aesData.append(p_mclearData->getData());
    }

    std::string getData()
        {
            return m_aesData;
        }

    std::string showDecryptedData(void)
    {
        m_aesData.erase(0,m_aesData.length());
        return m_aesData;
    }

};

Maintenant, disons que le type de décorateur est DES -

const std :: string desEncrypt = "DES Encrypted";

class des: public encryptionDecorator
{

private:

    std::string m_desData;

    des();

public:

    des(IclearData *pClearData): m_desData(desEncrypt)
    {
        p_mclearData = pClearData;
        m_desData.append(p_mclearData->getData());
    }

    std::string getData(void)
        {
            return m_desData;
        }

    std::string showDecryptedData(void)
    {
        m_desData.erase(0,desEncrypt.length());
        return m_desData;
    }

};

Créons un code client pour utiliser cette classe de décorateur -

int main()
{
    IclearData *pData = new clearData("HELLO_CLEAR_DATA");

    std::cout<<pData->getData()<<std::endl;


    encryptionDecorator *pAesData = new aes(pData);

    std::cout<<pAesData->getData()<<std::endl;

    encryptionDecorator *pDesData = new des(pAesData);

    std::cout<<pDesData->getData()<<std::endl;

    /** unwind the decorator stack ***/
    std::cout<<pDesData->showDecryptedData()<<std::endl;

    delete pDesData;
    delete pAesData;
    delete pData;

    return 0;
}

Vous verrez les résultats suivants -

HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
DES Encrypted AES Encrypted HELLO_CLEAR_DATA
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Destructor called
Destructor called of IclearData
Encryption Decorator Destructor called
Destructor called of IclearData
Destructor of clear Data Invoked
Destructor called of IclearData

Voici le diagramme UML - Représentation de classe de celui-ci. Dans le cas où vous souhaitez ignorer le code et vous concentrer sur l'aspect de conception.

entrez la description de l'image ici

agile
la source
1
l'exemple n'est-il pas plus adapté strategy pattern?
exexzian
@exexzian Oui, mes élèves me suggèrent constamment une liste de stratégies pour ce type de problème, et cela me semble aussi la solution la plus propre.
Josiah Yoder le
Non, avec le modèle de stratégie, vous ne pouvez pas combiner les méthodes de chiffrement. Auparavant, vous deviez créer une classe de stratégie pour chaque combinaison possible.
deetz
4

Le modèle Decorator vous aide à modifier ou configurer une fonctionnalité de votre objet en enchaînant avec d'autres sous-classes similaires de cet objet.

Le meilleur exemple serait les classes InputStream et OutputStream dans le package java.io

    File file=new File("target","test.txt");
    FileOutputStream fos=new FileOutputStream(file);
    BufferedOutputStream bos=new BufferedOutputStream(fos);
    ObjectOutputStream oos=new ObjectOutputStream(bos);


    oos.write(5);
    oos.writeBoolean(true);
    oos.writeBytes("decorator pattern was here.");


//... then close the streams of course.
Huseyin
la source
Dans ce cas, la chaîne d'appel commence à ObjectOutputStream, puis monte jusqu'à la classe File, puis la classe File renvoie la valeur, puis les trois autres sous-classes les ajoute toutes et enfin, la valeur de la méthode ObjectOutputStream la renvoie, est c'est correct?
Harvey Lin
3

Qu'est-ce que Decorator Design Pattern en Java.

La définition formelle du modèle Decorator du livre du GoF (Design Patterns: Elements of Reusable Object-Oriented Software, 1995, Pearson Education, Inc. Publishing as Pearson Addison Wesley) indique que vous pouvez,

"Attachez dynamiquement des responsabilités supplémentaires à un objet. Les décorateurs offrent une alternative flexible au sous-classement pour étendre les fonctionnalités."

Disons que nous avons une pizza et que nous voulons la décorer avec des garnitures telles que le poulet masala, l'oignon et le fromage mozzarella. Voyons comment l'implémenter en Java ...

Programme pour montrer comment implémenter Decorator Design Pattern en Java.

Pizza.java:

<!-- language-all: lang-html -->

package com.hubberspot.designpattern.structural.decorator;

public class Pizza {

public Pizza() {

}

public String description(){
    return "Pizza";
}

}



package com.hubberspot.designpattern.structural.decorator;

public abstract class PizzaToppings extends Pizza {

public abstract String description();

}

package com.hubberspot.designpattern.structural.decorator;

public class ChickenMasala extends PizzaToppings {

private Pizza pizza;

public ChickenMasala(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + " with chicken masala, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class MozzarellaCheese extends PizzaToppings {

private Pizza pizza;

public MozzarellaCheese(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "and mozzarella cheese.";
}
}



package com.hubberspot.designpattern.structural.decorator;

public class Onion extends PizzaToppings {

private Pizza pizza;

public Onion(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "onions, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class TestDecorator {

public static void main(String[] args) {

    Pizza pizza = new Pizza();

    pizza = new ChickenMasala(pizza);
    pizza = new Onion(pizza);
    pizza = new MozzarellaCheese(pizza);

    System.out.println("You're getting " + pizza.description());

}

}
Jonty
la source
3

J'ai beaucoup utilisé le motif Decorator dans mon travail. J'ai publié un article sur mon blog sur la façon de l'utiliser avec la journalisation.

Ismael
la source
Je n'aime pas que vous ayez juste jeté un lien comme réponse. Mais votre article de blog est si utile que je devais voter pour :). Maintenant je le comprends vraiment. Tout le monde vient avec une pizza, et vous avec un exemple parfait.
Niklas Raab
2

Le modèle décorateur vous permet d'ajouter dynamiquement un comportement aux objets.

Prenons un exemple où vous devez créer une application qui calcule le prix de différents types de hamburgers. Vous devez gérer différentes variantes de hamburgers, tels que «gros» ou «avec du fromage», dont chacun a un prix par rapport au hamburger de base. Par exemple, ajoutez 10 $ pour un hamburger avec du fromage, ajoutez 15 $ de plus pour un gros hamburger, etc.

Dans ce cas, vous pourriez être tenté de créer des sous-classes pour les gérer. Nous pourrions exprimer cela en Ruby comme suit:

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

Dans l'exemple ci-dessus, la classe BurgerWithCheese hérite de Burger et remplace la méthode de prix pour ajouter 15 $ au prix défini dans la super classe. Vous créeriez également une classe LargeBurger et définiriez le prix par rapport à Burger. Mais vous devez également définir une nouvelle classe pour la combinaison de «gros» et «avec fromage».

Maintenant, que se passe-t-il si nous devons servir un "hamburger avec frites"? Nous avons déjà 4 classes pour gérer ces combinaisons, et nous devrons en ajouter 4 supplémentaires pour gérer toutes les combinaisons des 3 propriétés - «grande», «avec fromage» et «avec frites». Nous avons besoin de 8 classes maintenant. Ajoutez une autre propriété et nous aurons besoin de 16. Cela deviendra 2 ^ n.

Essayons plutôt de définir un BurgerDecorator qui prend en charge un objet Burger:

class BurgerDecorator
  def initialize(burger)
    self.burger = burger
  end
end

class BurgerWithCheese < BurgerDecorator
  def price
    self.burger.price + 15
  end
end

burger = Burger.new
cheese_burger = BurgerWithCheese.new(burger)
cheese_burger.price   # => 65

Dans l'exemple ci-dessus, nous avons créé une classe BurgerDecorator, dont la classe BurgerWithCheese hérite. Nous pouvons également représenter la «grande» variation en créant la classe LargeBurger. Maintenant, nous pourrions définir un gros hamburger avec du fromage à l'exécution comme:

b = LargeBurger.new(cheese_burger)
b.price  # => 50 + 15 + 20 = 85

Rappelez-vous comment l'utilisation de l'héritage pour ajouter la variante "avec frites" impliquerait l'ajout de 4 sous-classes supplémentaires? Avec les décorateurs, nous créerions simplement une nouvelle classe, BurgerWithFries, pour gérer la nouvelle variante et gérer cela au moment de l'exécution. Chaque nouvelle propriété aurait besoin d'un peu plus de décorateur pour couvrir toutes les permutations.

PS. Ceci est la version courte d'un article que j'ai écrit sur l' utilisation du modèle de décorateur en Ruby , que vous pouvez lire si vous souhaitez découvrir des exemples plus détaillés.

Nithin
la source
2

Décorateur:

  1. Ajoutez un comportement à l'objet au moment de l'exécution . L'héritage est la clé pour atteindre cette fonctionnalité, qui est à la fois un avantage et un inconvénient de ce modèle.
  2. Il améliore le comportement de l'interface.
  3. Decorator peut être considéré comme un composite dégénéré avec un seul composant. Cependant, un décorateur ajoute des responsabilités supplémentaires - il n'est pas destiné à l'agrégation d'objets.
  4. La classe Decorator déclare une relation de composition à l'interface LCD (plus petit dénominateur de classe) et ce membre de données est initialisé dans son constructeur.
  5. Decorator est conçu pour vous permettre d'ajouter des responsabilités aux objets sans sous-classer

Se référer à la fabrication de sources article pour plus de détails.

Decorator (Abstract) : c'est une classe / interface abstraite, qui implémente l'interface du composant. Il contient l'interface des composants. En l'absence de cette classe, vous avez besoin de nombreuses sous-classes de ConcreteDecorators pour différentes combinaisons. La composition du composant réduit les sous-classes inutiles.

Exemple JDK:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
        char c = (char)bis.read();
        System.out.println("Char: "+c);;
}

Jetez un œil à la question SE ci-dessous pour des exemples de diagramme et de code UML.

Motif décorateur pour IO

Articles utiles:

journaldev

Wikipédia

Exemple de mot réel de modèle de décorateur: VendingMachineDecorator a été expliqué @

Quand utiliser le motif décorateur?

Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();

beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();

Dans l'exemple ci-dessus, le thé ou le café (boisson) a été décoré par Sugar and Lemon.

Ravindra babu
la source
2

Le modèle de décorateur atteint un seul objectif d' ajouter dynamiquement des responsabilités à n'importe quel objet .

Le modèle d'E / S Java est basé sur un modèle de décorateur.

Java IO comme modèle de décoration

ChandraBhan Singh
la source
1

Il existe un exemple sur Wikipedia sur la décoration d'une fenêtre avec une barre de défilement:

http://en.wikipedia.org/wiki/Decorator_pattern

Voici un autre exemple très «réel» de «membre d'équipe, chef d'équipe et gestionnaire», qui illustre que le modèle de décorateur est irremplaçable avec un simple héritage:

https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/

gm2008
la source
Ce lien Zishan Bilal est génial - meilleur exemple que j'ai vu
stonedauwg
1

Il y a quelque temps, j'avais refactoré une base de code en utilisant le modèle Decorator, donc je vais essayer d'expliquer le cas d'utilisation.

Supposons que nous ayons un ensemble de services et que l'utilisateur ait acquis ou non une licence d'un service particulier, nous devons démarrer le service.

Tous les services ont une interface commune

interface Service {
  String serviceId();
  void init() throws Exception;
  void start() throws Exception;
  void stop() throws Exception;
}

Pré refactoring

abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId, LicenseManager licenseManager) {
    // assign instance variables
  }

  @Override
  public void init() throws Exception {
    if (!licenseManager.isLicenseValid(serviceId)) {
       throw new Exception("License not valid for service");
    }
    // Service initialization logic
  }
}

Si vous observez attentivement, ServiceSupportdépend de LicenseManager. Mais pourquoi devrait-il en dépendre LicenseManager? Et si nous avions besoin d'un service d'arrière-plan qui n'a pas besoin de vérifier les informations de licence. Dans la situation actuelle, nous devrons en quelque sorte nous entraîner LicenseManagerpour revenirtrue aux services d'arrière-plan. Cette approche ne me paraissait pas bien. Selon moi, le contrôle de licence et les autres logiques étaient orthogonaux les uns par rapport aux autres.

Donc, modèle de décorateur vient à la rescousse et commence ici la refactorisation avec TDD.

Refactoring de poste

class LicensedService implements Service {
  private Service service;
  public LicensedService(LicenseManager licenseManager, Service service) {
    this.service = service;
  }

  @Override
  public void init() {
    if (!licenseManager.isLicenseValid(service.serviceId())) {
      throw new Exception("License is invalid for service " + service.serviceId());
    }
    // Delegate init to decorated service
    service.init();
  }

  // override other methods according to requirement
}

// Not concerned with licensing any more :)
abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId) {
    // assign variables
  }

  @Override
  public void init() {
    // Service initialization logic
  }
}

// The services which need license protection can be decorated with a Licensed service
Service aLicensedService = new LicensedService(new Service1("Service1"), licenseManager);
// Services which don't need license can be created without one and there is no need to pass license related information
Service aBackgroundService = new BackgroundService1("BG-1");

À emporter

  • La cohésion du code s'est améliorée
  • Les tests unitaires sont devenus plus faciles, car il n'est pas nécessaire de simuler une licence lors du test de ServiceSupport
  • Pas besoin de contourner les licences par des vérifications spéciales pour les services d'arrière-plan
  • Répartition appropriée des responsabilités
Narendra Pathai
la source
1

Prenons l'exemple de PubG. Les fusils d'assaut fonctionnent mieux avec un zoom 4x et pendant que nous y sommes, nous aurions également besoin d'un compensateur et d'un suppresseur. Cela réduira le recul et réduira le son de tir ainsi que l'écho. Nous devrons implémenter cette fonctionnalité qui permettra aux joueurs d'acheter leur arme préférée et leurs accessoires. Les joueurs peuvent acheter le pistolet ou une partie de l'accessoire ou tout l'accessoire et ils seraient facturés en conséquence.

Voyons comment le motif décorateur est appliqué ici:

Supposons que quelqu'un veuille acheter SCAR-L avec les trois accessoires mentionnés ci-dessus.

  1. Prenez un objet de SCAR-L
  2. Décorez (ou ajoutez) le SCAR-L avec un objet zoom 4x
  3. Décorez le SCAR-L avec un objet suppresseur
  4. Décorez le SCAR-L avec un objet compresseur
  5. Appelez la méthode de coût et laissez chaque objet déléguer l'ajout du coût en utilisant la méthode de coût des accessoires

Cela conduira à un diagramme de classes comme celui-ci:

Motif décorateur au travail

Maintenant, nous pouvons avoir des classes comme celle-ci:

public abstract class Gun {     
    private Double cost;    
    public Double getCost() {           
        return cost;        
       }    
    }

public abstract class GunAccessories extends Gun {  }

public class Scarl extends Gun {    
    public Scarl() {            
        cost = 100;
        }   
     }

public class Suppressor extends GunAccessories {        
    Gun gun;        
    public Suppressor(Gun gun) {            
    cost = 5;           
    this.gun = gun;     
    }               
    public double getCost(){            
        return cost + gun.getCost();
    }
}

public class GunShop{   
    public static void main(String args[]){         
    Gun scarl = new Scarl();                
    scarl = new Supressor(scarl);
    System.out.println("Price is "+scarl.getCost());
    }      
}

Nous pouvons également ajouter d'autres accessoires et décorer notre pistolet.

Référence:

https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/

HV
la source
0

Modèle de conception de décorateur : ce modèle permet de modifier les caractéristiques d'un objet lors de l'exécution. Il fournit différentes saveurs à un objet et donne la flexibilité de choisir les ingrédients que nous voulons utiliser dans cette saveur.

Exemple réel: disons que vous avez un siège principal dans la cabine d'un vol. Vous êtes désormais autorisé à choisir plusieurs équipements avec le siège. Chaque équipement a son propre coût qui lui est associé. Désormais, si un utilisateur choisit le Wifi et la nourriture premium, il / elle sera facturé pour siège + wifi + nourriture premium.

entrez la description de l'image ici

Dans ce cas, le modèle de conception de décorateur peut vraiment nous aider. Visitez le lien ci-dessus pour en savoir plus sur le modèle de décorateur et la mise en œuvre d'un exemple réel.

Ajit Singh
la source