Chain of Responsibility

(Redirecionado de Chain of Responsability)

Em Orientação a Objetos, Chain of Responsibility é um padrão GOF cuja principal função é evitar a dependência entre um objeto receptor e um objeto solicitante. Consiste em uma série de objetos receptores e de objetos de solicitação, onde cada objetos de solicitação possui uma lógica interna que separa quais são tipos de objetos receptores que podem ser manipulados. O restante é passado para o próximo objetos de solicitação da cadeia.

Devido a isso, é um padrão que utiliza a ideia de baixo acoplamento por permitir que outros objetos da cadeia tenham a oportunidade de tratar uma solicitação.

Estrutura editar

Passo-a-passo[1] editar

  • A base mantém um ponteiro como "próximo";
  • Cada classe derivada implementa sua própria contribuição para manusear o pedido (request);
  • Se o pedido precisa ser passado para outra classe, então a classe derivada "chama de volta" à classe padrão, delegando um novo ponteiro;
  • O cliente (terceirizado ou não) cria e encadeia a cadeia, a qual pode incluir uma ligação do último nó até o nó da raiz;
  • O cliente lança e deixa cada request com a raiz da cadeia;
  • As delegações recursivas produzem um efeito de ilusão;

Situações de Uso editar

  • Mais de um objeto pode tratar uma solicitação e o objeto que a tratará não é conhecido a priori;
  • O objeto que trata a solicitação deve ser escolhido automaticamente;
  • Deve-se emitir uma solicitação para um dentre vários objetos, sem especificar explicitamente o receptor;
  • O conjunto de objetos que pode tratar uma solicitação deveria ser especificado dinamicamente.

Em um sistema orientado a objetos esses interagem entre si através de mensagens, e o sistema necessita de determinar qual o objeto que irá tratar a requisição. O padrão de projeto Chain of Responsibility permite determinar quem será o objeto que irá tratar a requisição durante a execução. Cada objeto pode tratar ou passar a mensagem para o próximo na cascata.

Em um escritório, por exemplo, onde se tem 4 linhas telefônicas, a primeira linha é o primeiro objeto, a segunda linha é o segundo, e assim sucessivamente até a gravação automática que é o quinto objeto. Se a primeira linha estiver disponível ela irá tratar a ligação, se não ela passa a tarefa para o próximo objeto, que é a segunda linha. Se essa estiver ocupada ela passa a tarefa para a próxima e assim sucessivamente até que um objeto possa tratar a tarefa.

Nesse caso, se todas as linhas estiverem ocupadas o último objeto, que é a gravação automática, tratará da tarefa.

Exemplo editar

Java editar

Abaixo está um exemplo do padrão na linguagem de programação Java. Neste exemplo, temos atores diferentes, cada um estabelecendo um limite de compras à seu sucessor. Toda vez que um ator recebe um pedido de compra que exceda seu limite, o pedido é passado ao seu sucessor.

A classe abstrata PurchasePower com o método abstrato processRequest:

abstract class PurchasePower
{
    protected static final double BASE = 500;
    protected PurchasePower successor;

    abstract protected double getAllowable();

    abstract protected String getRole();

    public void setSuccessor(PurchasePower successor)
    {
        this.successor = successor;

    }

    public void processRequest(PurchaseRequest request)
    {
        if (request.getAmount() < this.getAllowable())
        {
            System.out.println(this.getRole() + " will approve $" + request.getAmount());
        }
        else if (successor != null)
        {
            successor.processRequest(request);
        }
    }
}

Temos quatro implementações da classe abstrata acima: Manager (Gerente), Director (Diretor), Vice President (Vice Presidente) e President (Presidente), cada uma multiplicando seu poder de compra:

class ManagerPPower extends PurchasePower
{
    protected double getAllowable()
    {
        return BASE*10;
    }

    protected String getRole()
    {
        return "Manager";
    }
}

class DirectorPPower extends PurchasePower
{
    protected double getAllowable()
    {
        return BASE*20;
    }

    protected String getRole()
    {
        return "Director";
    }
}

class VicePresidentPPower extends PurchasePower
{
    protected double getAllowable()
    {
        return BASE*40;
    }

    protected String getRole()
    {
        return "Vice President";
    }
}

class PresidentPPower extends PurchasePower
{
    protected double getAllowable()
    {
        return BASE*60;
    }

    protected String getRole()
    {
        return "President";
    }
}

O código abaixo define que a classe PurchaseRequest mantenha os dados em uma outra classe, como neste exemplo:

class PurchaseRequest
{

    private double amount;
    private String purpose;

    public PurchaseRequest(double amount, String purpose)
    {
        this.amount = amount;
        this.purpose = purpose;
    }

    public double getAmount()
    {
        return amount;
    }

    public void setAmount(double amt)
    {
        amount = amt;
    }

    public String getPurpose()
    {
        return purpose;
    }

    public void setPurpose(String reason)
    {
        purpose = reason;
    }
}

No uso que fizemos deste exemplo, temos a devida ordem (do menor poder de compra para o maior): Manager -> Director -> Vice President -> President

class CheckAuthority
{
    public static void main(String[] args)
    {
        ManagerPPower manager = new ManagerPPower();
        DirectorPPower director = new DirectorPPower();
        VicePresidentPPower vp = new VicePresidentPPower();
        PresidentPPower president = new PresidentPPower();
        manager.setSuccessor(director);
        director.setSuccessor(vp);
        vp.setSuccessor(president);

        // Press Ctrl+C to end.
        try
        {
            while (true)
            {
                System.out.println("Enter the amount to check who should approve your expenditure.");
                System.out.print(">");
                double d = Double.parseDouble(new BufferedReader(new InputStreamReader(System.in)).readLine());
                manager.processRequest(new PurchaseRequest(d, "General"));
            }
        } catch (Exception e)
        {
            System.exit(1);
        }
    }
}

Regras Importantes[1] editar

  • Chain of Responsibility, Command, Mediator, e Observer são como endereços, podendo ser separados entre remetentes e destinatários, mas com consequências diferentes. O Chain of Responsibility passa um pedido ao remetente junto com uma cadeia de potenciais destinatários.
  • Chain of Responsibility pode usar o padrão Command para representar pedidos como objetos.
  • Chain of Responsibility é frequentemente aplicado em conjunto com o padrão Composite. Os componentes da classe-mãe podem ser usados para a classe-filha também.

Referências externas editar

  1. a b «Design Patterns and Refactoring». sourcemaking.com. Consultado em 2 de outubro de 2016 

Ligações externas editar

  Este artigo sobre programação de computadores é um esboço. Você pode ajudar a Wikipédia expandindo-o.