Como os padrões de proxy, decorador, adaptador e ponte diferem?


403

Eu estava olhando para o Proxy Pattern, e para mim parece muito com os padrões Decorator, Adapter e Bridge. Estou entendendo mal alguma coisa? Qual é a diferença? Por que eu usaria o padrão Proxy versus os outros? Como você os usou no passado em projetos do mundo real?


4
Muitas vezes existem padrões que parecem muito semelhantes, mas diferem em suas intenções (os padrões de estratégia e estado vêm à mente). Eu acho que isso geralmente ocorre devido ao fato de os padrões de design serem baseados em princípios comuns de design sólidos.
2113 Jason Down

5
Bem, esses quatro padrões têm exatamente os mesmos detalhes de implementação. Versículos de estado A estratégia pode pelo menos ser resumida como versos completos de estado sem estado (na maior parte). Freqüentemente, a estratégia é apenas injeção de método, onde o padrão de estado usa uma interface para fazer mais do que abstrair uma chamada de método. A estratégia, também, no final do dia, é um truque para permitir a programação funcional no mundo OO.
Charles Graham

Respostas:


648

Proxy, Decorator, Adapter e Bridge são variações de "quebra" de uma classe. Mas seus usos são diferentes.

  • O proxy pode ser usado quando você deseja instanciar preguiçosamente um objeto, ocultar o fato de estar chamando um serviço remoto ou controlar o acesso ao objeto.

  • O Decorator também é chamado de "Proxy Inteligente". Isso é usado quando você deseja adicionar funcionalidade a um objeto, mas não estendendo o tipo desse objeto. Isso permite que você faça isso em tempo de execução.

  • O adaptador é usado quando você possui uma interface abstrata e deseja mapear essa interface para outro objeto que tenha função funcional semelhante, mas uma interface diferente.

  • Bridge é muito semelhante ao Adapter, mas chamamos de Bridge quando você define a interface abstrata e a implementação subjacente. Ou seja, você não está se adaptando a algum código herdado ou de terceiros, você é o designer de todo o código, mas precisa ser capaz de trocar implementações diferentes.

  • Fachada é uma interface de nível superior (leia-se: mais simples) para um subsistema de uma ou mais classes. Suponha que você tenha um conceito complexo que exija vários objetos para representar. Fazer alterações nesse conjunto de objetos é confuso, porque você nem sempre sabe qual objeto tem o método que precisa chamar. É o momento de escrever uma Fachada que fornece métodos de alto nível para todas as operações complexas que você pode fazer na coleção de objetos. Exemplo: um Modelo de Domínio para uma seção de escola, com métodos como countStudents(), reportAttendance(), assignSubstituteTeacher()e assim por diante.


7
Boa resposta. Pode valer a pena adicionar alguns exemplos de onde você o vê na natureza? por exemplo, classes de proxy nos serviços da Web. +1 de mim.
Rob Cooper

5
@ Rob: obrigado, mas eu prefiro manter essa resposta curta e doce. Convido você a escrever outra resposta com exemplos na natureza!
Bill Karwin 8/08/08

8
O @RobertDailey Decorator também é bom para evitar hierarquias do tipo fora de controle. Por exemplo , digamos que você tenha uma janela em uma GUI e deseje ter barras de rolagem opcionais. Você poderia ter as classes Window, VScrollWindow, HScrollWindow e VHScrollWindow ou criar decoradores VScroll e HScroll na Window.
Eva

11
@RobertDailey, Decorator é composição.
Bill Karwin

11
E se você deseja duplicar a interface do objeto agrupado 1: 1, mas depois adicionar alguns métodos adicionais? É um decorador ou um adaptador?
Donquixote

198

Como a resposta de Bill diz, seus casos de uso são diferentes .

O mesmo acontece com as estruturas deles.

  • Proxy e Decorator têm a mesma interface que seus tipos agrupados, mas o proxy cria uma instância sob o capô, enquanto o decorador cria uma instância no construtor.

  • O Adapter e o Facade têm uma interface diferente da que eles envolvem. Mas o adaptador deriva de uma interface existente, enquanto a fachada cria uma nova interface.

  • Ponte e adaptador apontam para um tipo existente. Mas a ponte apontará para um tipo abstrato e o adaptador poderá apontar para um tipo concreto. A ponte permitirá que você emparelhe a implementação em tempo de execução, enquanto o adaptador normalmente não.


30
Sua resposta combinada com a de Bill envolve 5 capítulos de Design Patterns muito bem. Pode-se chamá-los de uma interface de nível superior (leia-se: mais simples) do livro.
Jonas Eicher #

54

Minha opinião sobre o assunto.

Todos os quatro padrões têm muito em comum, todos os quatro são chamados informalmente de invólucros ou padrões de invólucro. Todos usam composição, agrupando o assunto e delegando a execução ao assunto em algum momento, mapeando uma chamada de método para outra. Eles poupam ao cliente a necessidade de construir um objeto diferente e copiar todos os dados relevantes. Se usados ​​com sabedoria, eles economizam memória e processador.

Ao promover o acoplamento flexível, eles tornam o código, uma vez estável, menos exposto a mudanças inevitáveis ​​e mais legível para outros desenvolvedores.

Adaptador

O adaptador adapta o assunto (adaptado) a uma interface diferente. Dessa forma, podemos adicionar objetos a uma coleção de tipos nominalmente diferentes.

O adaptador expõe apenas métodos relevantes ao cliente, pode restringir todos os outros, revelando intenções de uso para contextos específicos, como adaptar a biblioteca externa, fazer com que pareça menos geral e mais focado nas necessidades de nossos aplicativos. Os adaptadores aumentam a legibilidade e a auto descrição de nosso código.

Os adaptadores protegem uma equipe do código volátil de outras equipes; uma ferramenta de salvador de vidas ao lidar com equipes offshore ;-)

O objetivo menos mencionado é impedir que a classe de assunto exceda as anotações. Com tantas estruturas baseadas em anotações, isso se torna um uso mais importante do que nunca.

O adaptador ajuda a contornar a limitação de Java de apenas uma herança. Ele pode combinar vários adaptados em um envelope, dando a impressão de herança múltipla.

Em termos de código, o adaptador é "fino". Ele não deve adicionar muito código à classe adaptee, além de simplesmente chamar o método adaptee e ocasionais conversões de dados necessárias para fazer essas chamadas.

Não há muitos bons exemplos de adaptadores no JDK ou nas bibliotecas básicas. Os desenvolvedores de aplicativos criam adaptadores para adaptar bibliotecas a interfaces específicas de aplicativos.

Decorador

O Decorator não apenas delega, não apenas mapeia um método para outro, mas também modifica o comportamento de alguns métodos de assunto, pode decidir não chamar o método de assunto, delegar para um objeto diferente, um objeto auxiliar.

Decoradores normalmente adicionam funcionalidade (transparente) a objetos quebrados, como log, criptografia, formatação ou compactação ao assunto. Essa nova funcionalidade pode trazer muitos códigos novos. Portanto, os decoradores geralmente são muito mais "gordos" que os adaptadores.

O decorador deve ser uma subclasse da interface do sujeito. Eles podem ser usados ​​de forma transparente em vez de seus assuntos. Consulte BufferedOutputStream, ainda é OutputStream e pode ser usado como tal. Essa é uma grande diferença técnica dos adaptadores.

Exemplos de livros de texto de toda a família de decoradores estão prontamente no JDK - o Java IO. Todas as classes, como BufferedOutputStream , FilterOutputStream e ObjectOutputStream, são decoradoras de OutputStream . Eles podem ser em camadas de cebola, onde um decorador é decorado novamente, adicionando mais funcionalidade.

Proxy

O proxy não é um wrapper típico. O objeto agrupado, o assunto do proxy, ainda não pode existir no momento da criação do proxy. O proxy geralmente o cria internamente. Pode ser um objeto pesado criado sob demanda ou é um objeto remoto em JVM diferente ou em um nó de rede diferente e até mesmo um objeto não Java, um componente no código nativo. Ele não precisa envolver ou delegar a outro objeto.

Os exemplos mais comuns são proxies remotos, inicializadores de objetos pesados ​​e proxies de acesso.

  • Proxy Remoto - o assunto está no servidor remoto, em JVM diferente ou mesmo em um sistema não Java. O proxy converte chamadas de método para chamadas RMI / REST / SOAP ou o que for necessário, protegendo o cliente da exposição à tecnologia subjacente.

  • Lazy Load Proxy - inicialize totalmente o objeto apenas no primeiro uso ou no primeiro uso intensivo.

  • Proxy de acesso - controle o acesso ao assunto.

Fachada

Fachada está intimamente associada ao Princípio do Menos Conhecimento do Projeto (Lei de Demeter). Fachada é muito semelhante ao adaptador. Ambos envolvem, ambos mapeiam um objeto para outro, mas diferem na intenção. Fachada nivela a estrutura complexa de um assunto, gráfico de objetos complexos, simplificando o acesso a uma estrutura complexa.

Fachada envolve uma estrutura complexa, fornecendo uma interface plana para ela. Isso evita que o objeto cliente seja exposto a relações internas na estrutura do sujeito, promovendo assim um acoplamento flexível.

Ponte

Variante mais complexa do padrão do adaptador, onde não apenas a implementação varia, mas também a abstração. Acrescenta mais um indireto à delegação. A delegação extra é a ponte. Ele desacopla o adaptador até da interface de adaptação. Aumenta a complexidade mais do que qualquer outro padrão de empacotamento, portanto, aplique com cuidado.

Diferenças nos construtores

Diferenças de padrão também são óbvias quando se olha para seus construtores.

  • O proxy não está quebrando um objeto existente. Não há assunto no construtor.

  • O Decorator e o Adapter envolvem o objeto já existente, e isso geralmente é
    fornecido no construtor.

  • O construtor Facade pega o elemento raiz de um gráfico de objeto inteiro, caso contrário, parece o mesmo que o Adapter.

Exemplo da vida real - Adaptador Marshalling JAXB . O objetivo deste adaptador é mapear uma classe simples e plana para uma estrutura mais complexa requerida externamente e evitar a classe de assunto "poluente" com anotações excessivas.


30

Há muita sobreposição em muitos dos padrões GoF. Todos eles são construídos com base no poder do polimorfismo e, às vezes, diferem apenas na intenção. (estratégia vs. estado)

Minha compreensão dos padrões aumentou 100 vezes depois de ler Head First Design Patterns .

Eu recomendo!


9

Todas as boas respostas de especialistas já explicaram o que significa cada padrão.

Vou decorar pontos-chave.

Decorador:

  1. Adicionar comportamento ao objeto em tempo de execução . A herança é a chave para alcançar essa funcionalidade, que é a vantagem e a desvantagem desse padrão.
  2. Ele modifica o comportamento da interface.

por exemplo (com encadeamento): java.ioclasses de pacotes relacionadas a InputStream& OutputStreaminterfaces

FileOutputStream fos1 = new FileOutputStream("data1.txt");  
ObjectOutputStream out1 = new ObjectOutputStream(fos1);

Proxy:

  1. Use-o para inicialização lenta, melhoria de desempenho, armazenando em cache o objeto e controlando o acesso ao cliente / chamador . Pode fornecer comportamento alternativo ou chamar objeto real. Durante esse processo, ele pode criar um novo objeto.
  2. Ao contrário do Decorator , que permite encadeamento de objetos, o Proxy não permite encadeamento.

por exemplo: java.rmiclasses de pacotes.

Adaptador:

  1. Ele permite que duas interfaces não relacionadas trabalhem juntas através de diferentes objetos , possivelmente desempenhando o mesmo papel.
  2. Modifica a interface original .

por exemplo java.io.InputStreamReader( InputStreamretorna a Reader)

Ponte:

  1. Permite que abstrações e implementações variem independentemente .
  2. Ele usa composição sobre herança .

por exemplo, classes de coleção em java.util. Listimplementado por ArrayList.

Notas principais:

  1. O adaptador fornece uma interface diferente para o assunto. O proxy fornece a mesma interface. O Decorator fornece uma interface aprimorada.
  2. O adaptador altera a interface de um objeto, o Decorator aprimora as responsabilidades de um objeto.
  3. O Decorator e o Proxy têm finalidades diferentes, mas estruturas semelhantes
  4. O adaptador faz as coisas funcionarem após serem projetadas; Bridge os faz trabalhar antes de serem.
  5. O Bridge é projetado antecipadamente para permitir que a abstração e a implementação variem independentemente. O adaptador é adaptado para fazer com que classes não relacionadas funcionem juntas
  6. O Decorator foi projetado para permitir adicionar responsabilidades aos objetos sem subclassificar.

Dê uma olhada nas ótimas perguntas / artigos do SE sobre exemplos de vários padrões de design

Quando usar o padrão do decorador?

Quando você usa o padrão de ponte? Como é diferente do padrão do adaptador?

Diferenças entre Proxy e Padrão Decorador


8

Eles são bastante semelhantes, e as linhas entre eles são bastante cinzas. Sugiro que você leia as entradas Padrão de proxy e Padrão de decorador no wiki do c2.

As entradas e discussões são bastante extensas e também possuem links para outros artigos relevantes. A propósito, o wiki c2 é excelente quando se pergunta sobre as nuances entre os diferentes padrões.

Para resumir as entradas c2, eu diria que um decorador adiciona / altera o comportamento, mas um proxy tem mais a ver com controle de acesso (instanciação lenta, acesso remoto, segurança etc.). Mas, como eu disse, as linhas entre elas são cinza e vejo referências a proxies que podem ser facilmente visualizados como decoradores e vice-versa.


4

Todos os quatro padrões envolvem a quebra de objetos / classes internos com os externos, portanto, são estruturalmente muito semelhantes. Eu descreveria a diferença com o objetivo:

  • O proxy encapsula o acesso de externo a interno.
  • O decorador modifica ou estende o comportamento de interno com externo.
  • O adaptador converte a interface de interna para externa.
  • A ponte separa parte invariável do comportamento (externo) da variável ou parte dependente da plataforma (interna).

E pela variação da interface entre objetos internos e externos:

  • nas interfaces de proxy são as mesmas.
  • nas interfaces do Decorator são iguais.
  • As interfaces do adaptador são diferentes formalmente, mas cumprem o mesmo objetivo.
  • nas interfaces Bridge são diferentes conceitualmente.

4

Citação de Head First Design Patterns

As definições pertencem ao livro. Exemplos me pertence.

Decorador - Não altera a interface, mas agrega responsabilidade. Suponha que você tenha uma interface de carro. Ao implementar isso para diferentes modelos de carro (s, sv, sl), você pode precisar adicionar mais responsabilidades para alguns modelos. Como tem teto solar, airbag etc.

Adaptador - Converte uma interface para outra. Você tem uma interface de carro e gostaria que ele agisse como um jipe. Então você pega o carro, modifica e vira um jipe. Uma vez que não é um jipe ​​de verdade. Mas age como um jipe.

Fachada - simplifica a interface. Suponha que você tenha interfaces de carro, avião, navio. Na verdade, tudo o que você precisa é de uma classe que envie pessoas de um local para outro. Você quer que a fachada decida qual veículo usar. Então você coleta todas essas referências de interface sob um guarda-chuva e deixa que ele decida / delegue para simplificar.

Head First: "Uma fachada não apenas simplifica uma interface, mas desacopla um cliente de um subsistema de componentes. Fachadas e adaptadores podem agrupar várias classes, mas a intenção de uma fachada é simplificar, enquanto o adaptador é converter a interface em algo diferente. "


1

Eu o uso com bastante frequência ao consumir serviços da web. O Proxy Pattern provavelmente deve ser renomeado para algo mais pragmático, como 'Wrapper Pattern ". Também tenho uma biblioteca que é um Proxy para o MS Excel. Torna muito fácil automatizar o Excel, sem ter que se preocupar com detalhes de plano de fundo, como o que versão está instalada (se houver).


Isso não seria apenas o padrão do adaptador?
Charles Graham

11
Um serviço da Web é consumido por um Proxy, enquanto o Padrão do Adaptador é usado mais para a conversão ou tradução de dados de um formulário para outro.
hmcclungiii 08/12/08

1

Falando na implementação detalhada, encontro uma diferença entre Proxy e Decorator, Adapter, Facade ... Na implementação comum desses padrões, há um objeto de destino envolvido por um objeto de fechamento. O cliente usa o objeto anexo em vez do objeto de destino. E o objeto de destino realmente desempenha um papel importante em alguns métodos de inclusão de objetos.

No entanto, no caso do Proxy, o objeto envolvente pode executar alguns métodos por si só, apenas inicializa o objeto de destino quando o cliente chama alguns métodos dos quais ele precisa participar. Essa é uma inicialização lenta. No caso de outros padrões, o objeto anexo é praticamente baseado no objeto de destino. Portanto, o objeto de destino é sempre inicializado junto com o objeto envolvente nos construtores / setters.

Outra coisa, um proxy faz exatamente o que um destino faz, enquanto outros padrões adicionam mais funcionalidade ao destino.


1

Gostaria de adicionar exemplos à resposta de Bill Karwing (o que é ótimo). Eu também adiciono algumas diferenças importantes de implementação, que sinto que estão faltando

As partes citadas são da resposta de [ https://stackoverflow.com/a/350471/1984346] (Bill Karwing)

Proxy, Decorator, Adapter e Bridge são variações de "quebra" de uma classe. Mas seus usos são diferentes.

  • O proxy pode ser usado quando você deseja instanciar preguiçosamente um objeto, ocultar o fato de estar chamando um serviço remoto ou controlar o acesso ao objeto.

ProxyClass e ObjectClass com proxy, devem implementar a mesma interface, para que sejam intercambiáveis

Exemplo - objeto caro de proxy

class ProxyHumanGenome implements GenomeInterface  {
    private $humanGenome = NULL; 

    // humanGenome class is not instantiated at construct time
    function __construct() {
    }

    function getGenomeCount() {
        if (NULL == $this->humanGenome) {
            $this->instantiateGenomeClass(); 
        }
        return $this->humanGenome->getGenomeCount();
    }
} 
class HumanGenome implement GenomeInterface { ... }
  • O Decorator também é chamado de "Proxy Inteligente". Isso é usado quando você deseja adicionar funcionalidade a um objeto, mas não estendendo o tipo desse objeto. Isso permite que você faça isso em tempo de execução.

DecoratorClass deve (poderia) implementar uma interface estendida de ObjectClass. Portanto, o ObjectClass pode ser substituído pelo DecoratorClass, mas não vice-versa.

Exemplo - adicionando funcionalidade adicional

class DecoratorHumanGenome implements CheckGenomeInterface  {

    // ... same code as previous example

    // added functionality
    public function isComplete() {
        $this->humanGenome->getCount >= 21000
    }
}

interface CheckGenomeInterface extends GenomeInterface {

    public function isComplete();

}

class HumanGenome implement GenomeInterface { ... }
  • O adaptador é usado quando você possui uma interface abstrata e deseja mapear essa interface para outro objeto que tenha função funcional semelhante, mas uma interface diferente.

Diferenças de implementação Proxy, Decorador, Adaptador

O adaptador fornece uma interface diferente para o assunto. O proxy fornece a mesma interface. O Decorator fornece uma interface aprimorada.

  • Bridge é muito semelhante ao Adapter, mas chamamos de Bridge quando você define a interface abstrata e a implementação subjacente. Ou seja, você não está se adaptando a algum código herdado ou de terceiros, você é o designer de todo o código, mas precisa ser capaz de trocar implementações diferentes.

  • Fachada é uma interface de nível superior (leia-se: mais simples) para um subsistema de uma ou mais classes. Suponha que você tenha um conceito complexo que exija vários objetos para representar. Fazer alterações nesse conjunto de objetos é confuso, porque você nem sempre sabe qual objeto tem o método que precisa chamar. É o momento de escrever uma Fachada que fornece métodos de alto nível para todas as operações complexas que você pode fazer na coleção de objetos. Exemplo: um Modelo de Domínio para uma seção de escola, com métodos como countStudents(), reportAttendance(), assignSubstituteTeacher()e assim por diante.

A maioria das informações nesta resposta é de https://sourcemaking.com/design_patterns , que eu recomendo como um excelente recurso para padrões de design.


0

Eu acredito que o código dará uma ideia clara (para complementar as respostas de outras pessoas também). Veja abaixo (concentre os tipos que uma classe implementa e envolve)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Proxy */

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("PROXY");
            Console.WriteLine(Environment.NewLine);

            //instead of creating here create using a factory method, the facory method will return the proxy
            IReal realProxy = new RealProxy();
            Console.WriteLine("calling do work with the proxy object ");
            realProxy.DoWork();

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("ADAPTER");
            Console.WriteLine(Environment.NewLine);

            /*Adapter*/
            IInHand objectIHave = new InHand();
            Api myApi = new Api();
            //myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */
            IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave);
            Console.WriteLine("calling api with  my adapted obj");
            myApi.SomeApi(myAdaptedObject);


            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("DECORATOR");
            Console.WriteLine(Environment.NewLine);

            /*Decorator*/
            IReady maleReady = new Male();
            Console.WriteLine("now male is going to get ready himself");
            maleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReady = new Female();
            Console.WriteLine("now female is going to get ready her self");
            femaleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady maleReadyByBeautician = new Beautician(maleReady);
            Console.WriteLine("now male is going to get ready by beautician");
            maleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReadyByBeautician = new Beautician(femaleReady);
            Console.WriteLine("now female is going to get ready by beautician");
            femaleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            Console.ReadLine();


        }
    }

    /*Proxy*/

    public interface IReal
    {
        void DoWork();
    }

    public class Real : IReal
    {
        public void DoWork()
        {
            Console.WriteLine("real is doing work ");
        }
    }


    public class RealProxy : IReal
    {
        IReal real = new Real();

        public void DoWork()
        {
            real.DoWork();
        }
    }

    /*Adapter*/

    public interface IActual
    {
        void DoWork();
    }

    public class Api
    {
        public void SomeApi(IActual actual)
        {
            actual.DoWork();
        }
    }

    public interface IInHand
    {
        void DoWorkDifferently();
    }

    public class InHand : IInHand
    {
        public void DoWorkDifferently()
        {
            Console.WriteLine("doing work slightly different ");
        }
    }

    public class ActualAdapterForInHand : IActual
    {
        IInHand hand = null;

        public ActualAdapterForInHand()
        {
            hand = new InHand();
        }

        public ActualAdapterForInHand(IInHand hnd)
        {
            hand = hnd;
        }

        public void DoWork()
        {
            hand.DoWorkDifferently();
        }
    }

    /*Decorator*/

    public interface IReady
    {
        void GetReady();
    }

    public class Male : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
        }
    }

    public class Female : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
            Console.WriteLine("Make up....");
        }
    }

    //this is a decorator
    public class Beautician : IReady
    {
        IReady ready = null;

        public Beautician(IReady rdy)
        {
            ready = rdy;
        }

        public void GetReady()
        {
            ready.GetReady();
            Console.WriteLine("Style hair ");

            if (ready is Female)
            {
                for (int i = 1; i <= 10; i++)
                {
                    Console.WriteLine("doing ready process " + i);
                }

            }
        }
    }

}

-3

O padrão de design não é matemática, é uma combinação de arte e engenharia de software. Para esse requisito, não há nada que você precise usar proxy, ponte etc. Os padrões de design são criados para resolver os problemas. Se você antecipar um problema de design, use-o. Com base na experiência, você conhecerá um problema específico, qual padrão usar. Se você é bom em sólidos princípios de design, teria implementado o padrão de design sem saber que é padrão. Exemplo comum é padrões estéticos e de fábrica

Portanto, concentre-se mais em princípios sólidos de design, princípios de codificação limpos e ttd


Concordo, embora não esteja respondendo à pergunta.
294 Leon
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.