Skip to main content

Les chaines de responsabilités

La chaine de responsabilité est un moyen de faire beaucoup de traitement sur un même objet. Cela peut être un très bon moyen de gérer une cascade de conditions if dans un code. Ainsi chaque bloc de if est séparé et sont liés entre eux. Cela permet aussi d'isoler ces différentes vérifications dans des fichiers séparés.

2023-10-03_19-50-33_screenshot.png

A noter que ce schéma utilise l'héritage mais qu'il faut toujours préférer la composition à l'héritage, il vaut donc mieux simplement avoir des ConcreteHandlers qui implémentent tous Handler.

Aussi pour simplifier l'écriture on peut simplement mettre le setNext dans le constructeur du Handler (ce qui permet de rendre la chaine plus propre par après)

Exemple

Code avant

Voici l'horrible code à réorganiser :

package com.gildedrose;

class GildedRose {
    Item[] items;

    public GildedRose(Item[] items) {
        this.items = items;
    }

    public void updateQuality() {
        for (int i = 0; i < items.length; i++) {
            if (!items[i].name.equals("Aged Brie")
                    && !items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                if (items[i].quality > 0) {
                    if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                        items[i].quality = items[i].quality - 1;
                    }
                }
            } else {
                if (items[i].quality < 50) {
                    items[i].quality = items[i].quality + 1;

                    if (items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                        if (items[i].sellIn < 11) {
                            if (items[i].quality < 50) {
                                items[i].quality = items[i].quality + 1;
                            }
                        }

                        if (items[i].sellIn < 6) {
                            if (items[i].quality < 50) {
                                items[i].quality = items[i].quality + 1;
                            }
                        }
                    }
                }
            }

            if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                items[i].sellIn = items[i].sellIn - 1;
            }

            if (items[i].sellIn < 0) {
                if (!items[i].name.equals("Aged Brie")) {
                    if (!items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                        if (items[i].quality > 0) {
                            if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                                items[i].quality = items[i].quality - 1;
                            }
                        }
                    } else {
                        items[i].quality = items[i].quality - items[i].quality;
                    }
                } else {
                    if (items[i].quality < 50) {
                        items[i].quality = items[i].quality + 1;
                    }
                }
            }
        }
    }
}

Code après

Et voici ce que l'on obient en utilisant le patron de la chaine de reponsabilités.

  • Classe principale GildedRose :
package com.gildedrose;

import com.gildedrose.handlers.*;

class GildedRose {
    Item[] items;

    public GildedRose(Item[] items) {
        this.items = items;
    }

    public void updateQuality() {
        // On enchaine les handlers
        // Ainsi Sulfuras >> AgedBrie >> BackStage >> Default
        Handler handlers = new Sulfuras(new AgedBrie(new Backstage(new Default())));

        for (int i = 0; i < items.length; i++)
            handlers.update(items[i]);
    }
}
  • L'interface Handler
package com.gildedrose.handlers;

import com.gildedrose.Item;

public interface Handler {
    void update(Item item);
}
  • Les différentes classes implémentant Handler (notez qu'ici toutes les classes sont mise au même endroit, mais dans le projet elles sont dans des fichiers séparés)
package com.gildedrose.handlers;

import com.gildedrose.Item;

public class AgedBrie implements Handler {
    private Handler next = null;

    public AgedBrie(Handler next) {
        this.next = next;
    }

    @Override
    public void update(Item item) {
        if (item.name.equals("Aged Brie")) {
            item.sellIn--;
            if (item.quality < 50)
                item.quality++;
            if (item.sellIn < 0 && item.quality < 50)
                item.quality++;
        }

        else if (next != null)
            next.update(item);
    }

}

public class Backstage implements Handler {
    private Handler next = null;

    public Backstage(Handler next) {
        this.next = next;
    }

    @Override
    public void update(Item item) {
        if (item.name.equals("Backstage passes to a TAFKAL80ETC concert")) {
            if (item.quality < 50)
                item.quality++;
            if (item.sellIn < 11 && item.quality < 50)
                item.quality++;
            if (item.sellIn < 6 && item.quality < 50)
                item.quality++;

            // I have no idea what this shit does
            if (item.sellIn < 0)
                item.quality = item.quality - item.quality;
        } else if (next != null) {
            next.update(item);
        }
    }

}

public class Default implements Handler {
    @Override
    public void update(Item item) {
        if (item.quality > 0) {
            item.quality--;
            item.sellIn--;
            if (item.sellIn < 0)
                item.quality--;
        }
    }
}

public class Sulfuras implements Handler {
    private Handler next = null;

    public Sulfuras(Handler next) {
        this.next = next;
    }

    @Override
    public void update(Item item) {
        if (item.name.equals("Sulfuras, Hand of Ragnaros"))
            return;
        if (next != null)
            next.update(item);
    }
}