Decorator

Solução Proposta

Permite acrescentar responsabilidades a objetos individuais de forma dinâmica e transparente, sem afetar outros objetos.

Vantagens

Desvantagens

Exemplo

Em um jogo lutadores de MMA (Mixed Martial Arts) brasileiros e japoneses utilizam diversos estilos de arte marcial (karatê, judô e jui-jitsu). Durante a luta eles podem mudar a arte utilizada nos golpes para ataque e defesa. O jogador atuando como técnico decide como configurar cada lutador de acordo com esses diferentes estilos de arte marcial. 

A implementação da abstração Fighter é organizada em duas hierarquias de classes separadas, uma hierarquia básica para variação das nacionalidades dos lutadores (BrazilianFighter, JapaneseFighter) e outra hierarquia de decoradores para variação das artes marciais dos lutadores (Karate, Judo, Jiu-Jitsu). MartialArt (Decorator) é um Fighter e mantém uma referência para outro objeto Fighter (Component) e delega a execução dos golpes para esse objeto. Suas subclasses (Concrete Decorators) redefinem os métodos de golpes herdados acrescentando comportamentos extras antes e/ou depois da delegação, permitindo combinar as duas hierarquias sem ter que criar uma classe para cada possível combinação evitando, assim, uma explosão de classes. 

Diagrama de Classe

Decorator - Diagrama

Participantes

  • Component (Fighter): Define uma interface para objetos que podem ter responsabilidades acrescentadas dinamicamente.
  • ConcreteComponent (BrazilianFighter, JapaneseFighter): Define um objeto que pode ser decorado com novas responsabilidades.
  • Decorator (MartialArt): Mantém uma referência para um objeto Component e define uma interface que segue a interface de Component.
  • ConcreteDecorator (Karate, Judo, Jui-Jitsu): Acrescenta responsabilidades ao objeto do tipo Component.

Código

/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public class JiuJitsu extends MartialArtDecorator {

    public JiuJitsu(Fighter fighter) {
        super(fighter);
    }

    @Override
    public void toAttack() {
        component.toAttack();
        System.out.println("Attacking like a Jujitsuka!");
    }

    @Override
    public void defend() {
        component.defend();
        System.out.println("Defeding like a Jujitsuka!");
    }

}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

/**
 *
 * @author Adriano Gonçalves
 */
public class BrazillianFighter extends FighterImpl {

    @Override
    public void toAttack() {
        System.out.println("Beginning a Brazillian attack!");

    }

    @Override
    public void defend() {
        System.out.println("Defending a Brazillian defence!");
    }
}
package com.padroesdr.decorator.exemplos.mma;

public class Principal {

    public static void main(String args[]) {

        System.out.println("Fighter 1:");

        Fighter fighter1 = new JapaneseFighter();

        fighter1 = new Karate(fighter1);

        fighter1.toAttack();

        fighter1.defend();

        // Changing the martial art in runtime
        System.out.println("Changing the Japanese martial art in runtime...");

        /* The following lines aim to "undecorate" the last martial art, due to the only one martial art at time request
         * from this problem.
         * This approach is only for making this example simpler, for learning purposes. A desirable approach would be
         * creating all the instances through the Factory pattern, and controlling the decorations and undecorations
         * inside a manager class.
         */
        if (fighter1 instanceof MartialArtDecorator) {
            fighter1 = ((MartialArtDecorator) fighter1).getComponent();
        }

        fighter1 = new Judo(fighter1);

        fighter1.toAttack();

        fighter1.defend();

        System.out.println("Fighter 2:");
        Fighter fighter2 = new BrazillianFighter();

        fighter2 = new JiuJitsu(fighter2);

        fighter2.toAttack();

        fighter2.defend();
    }

}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public abstract class FighterImpl implements Fighter {

    @Override
    public abstract void toAttack();

    @Override
    public abstract void defend();

}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public interface Fighter {

    public void toAttack();

    public void defend();

}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public abstract class MartialArtDecorator implements Fighter {

    protected Fighter component;

    public MartialArtDecorator(Fighter component) {
        this.component = component;
    }

    @Override
    public abstract void toAttack();

    @Override
    public abstract void defend();

    // Houston, we've got a problem!
    public Fighter getComponent() {
        return this.component;
    }

}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public class MartialArtManager {

    private static MartialArtManager instance;

    public MartialArtManager getSoleInstance() {
        if (instance == null) {
            instance = new MartialArtManager();
        }

        return instance;
    }

    public static void setMartialArt(Fighter fighter) {

    }
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public class Karate extends MartialArtDecorator {

    public Karate(Fighter fighter) {
        super(fighter);
    }

    @Override
    public void toAttack() {
        component.toAttack();
        System.out.println("Attacking like a Karateka!");
    }

    @Override
    public void defend() {
        component.defend();
        System.out.println("Defeding like a Karateka!");
    }

}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

/**
 *
 * @author Adriano Gonçalves
 */
public class JapaneseFighter extends FighterImpl {

    @Override
    public void toAttack() {
        System.out.println("Beginning a Japanese attack!");

    }

    @Override
    public void defend() {
        System.out.println("Defending a Japanese defence!");
    }
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.padroesdr.decorator.exemplos.mma;

public class Judo extends MartialArtDecorator {

    public Judo(Fighter fighter) {
        super(fighter);
    }

    @Override
    public void toAttack() {
        component.toAttack();
        System.out.println("Attacking like a Judoka!");
    }

    @Override
    public void defend() {
        component.defend();
        System.out.println("Defeding like a Judoka!");
    }

}
Clique aqui para fazer o download do código completo de implementação deste Design Pattern.

Padrões Relacionados