English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Este artigo exemplifica o padrão Builder no design de programação Android. Compartilho com vocês para referência, conforme a seguir:
Primeiro, introdução
O padrão Builder é um padrão de criação que cria um objeto complexo passo a passo, permitindo que o usuário controle mais finamente o processo de construção do objeto sem saber os detalhes internos de construção. Este padrão é para desacoplar o processo de construção do objeto de seus componentes, permitindo que o processo de construção e a representação dos componentes sejam isolados.
Porque um objeto complexo tem muitas partes componentes, por exemplo, um carro tem rodas, volante, motor e várias pequenas peças, como como montar essas peças em um carro, este processo de montagem é longo e complexo, para esse tipo de situação, para ocultar detalhes de implementação externos durante o processo de construção, você pode usar o padrão Builder para separar componentes e processo de montagem, tornando o processo de construção e componentes ambos flexíveis e minimizando a耦合 entre eles.
Segundo, definição
Separar a construção de um objeto complexo de sua representação, permitindo que o mesmo processo de construção crie diferentes representações.
Terceiro, cenário de uso
(1Quando métodos idênticos, com diferentes ordens de execução, resultam em diferentes resultados de eventos.
(2Quando vários componentes ou peças podem ser montados em um objeto, mas os resultados de execução gerados não são os mesmos.
(3Quando a classe de produto é muito complexa ou a ordem de chamada da classe de produto é diferente, resultando em diferentes efeitos, neste momento, usar o padrão Builder é muito apropriado.
(4Quando a inicialização de um objeto é particularmente complexa, como muitos parâmetros e muitos desses parâmetros têm valores padrão.
Quarto, Diagrama de Classes UML do Padrão Builder
Introdução aos papéis:
Product classe de produto - classe abstrata do produto;
Builder - classe Builder abstrata, que normatiza a montagem do produto, geralmente implementada por subclasses para concretizar o processo de montagem;
ConcreateBuilder - classe Builder específica;
Director - processo de montagem unificado;
V, Implementação simples do padrão Builder
O processo de montagem do computador é bastante complexo e a ordem de montagem não é fixa, para facilitar a compreensão, simplificamos o processo de montagem do computador para construir o anfitrião, configurar o sistema operacional e configurar o monitor3partes, e então através do Director e do Builder específico para construir o objeto do computador.
Exemplo de código:
/** * classe abstrata de computador, ou papel de Produto */ public abstract class Computer { protected String mBoard; protected String mDisplay; protected String mOS; protected Computer(){} /** * configurar placa-mãe * @param board */ public void setBoard(String board){ this.mBoard = board; } /** * configurar monitor * @param display */ public void setDisplay(String display){ this.mDisplay = display; } /** * Set operating system */ public abstract void setOS(); @Override public String toString(){ return "Computer [mBoard=" + mBoard + ", mDisplay=" + mDisplay + ", mOS=" + mOS + "]"; } }
/** * classe específica Computer, Macbook */ public class Macbook extends Computer { protected Macbook(){} @Override public void setOS() { mOS = "Mac OS X 10"; } }
/** * classe Builder abstrata */ public abstract class Builder { /** * configurar anfitrião * @param board */ public abstract void buildBoard(String board); /** * configurar monitor * @param display */ public abstract void buildDisplay(String display); /** * Set operating system */ public abstract void buildOS(); /** * Create Computer * @return */ public abstract Computer create(); }
/** * Specific Builder class, MacbookBuilder */ public class MacbookBuilder extends Builder { private Computer mComputer = new Macbook(); @Override public void buildBoard(String board) { mComputer.setBoard(board); } @Override public void buildDisplay(String display) { mComputer.setDisplay(display); } @Override public void buildOS() { mComputer.setOS(); } @Override public Computer create() { return mComputer; } }
/** * Director class, responsible for constructing Computer */ public class Director { Builder mBuilder = null; public Director(Builder builder){ mBuilder = builder; } /** * Build object * @param board Motherboard * @param display Display */ public void construct(String board, String display){ mBuilder.buildBoard(board); mBuilder.buildDisplay(display); mBuilder.buildOS(); } }
/** * Test code */ public class Test { public static void main(String[] args){ //Builder Builder builder = new MacbookBuilder(); //Director Director pcDirector = new Director(builder); //Encapsulation construction process pcDirector.construct("Intel Motherboard", "Retina Display"); //Construa um computador e exiba informações relevantes System.out.println("Computer Info: " + builder.create().toString()); } }
Resultados de saída:
Computer Info: Computer [mBoard=Intel Motherboard, mDisplay=Retina Display, mOS=Mac OS X 10]
No exemplo acima, é usado o MacbookBuilder específico para construir o objeto Macbook, enquanto o Director encapsula o processo de construção do objeto produto complexo, ocultando os detalhes de construção. O Builder e o Director juntos separam a construção de um objeto complexo de sua representação, permitindo que o mesmo processo de construção crie diferentes objetos.
Vale notar que, no processo de desenvolvimento real, o papel do Director frequentemente é omitido. Em vez disso, é usado um Builder para montar o objeto, que geralmente é uma chamada encadeada. O ponto crucial é que cada método setter retorna a si mesmo, ou seja, return this, o que permite que os métodos setter sejam chamados encadeados. O código é mais ou menos assim:
new TestBuilder() .setA("A") .create();
Desta forma, não apenas é removido o papel do Director, a estrutura também se torna mais simples e permite um controle mais fino do processo de montagem do objeto Product.
Seis, variação do padrão Builder - chamada encadeada
Exemplo de código:
public class User { private final String name; //obrigatório private final String cardID; //obrigatório private final int age; //opcional private final String address; //opcional private final String phone; //opcional private User(UserBuilder userBuilder){ this.name=userBuilder.name; this.cardID=userBuilder.cardID; this.age=userBuilder.age; this.address=userBuilder.address; this.phone=userBuilder.phone; } public String getName() { return name; } public String getCardID() { return cardID; } public int getAge() { return age; } public String getAddress() {}} return address; } public String getPhone() { return phone; } public static class UserBuilder{ private final String name; private final String cardID; private int age; private String address; private String phone; public UserBuilder(String name,String cardID){ this.name=name; this.cardID=cardID; } public UserBuilder age(int age){ this.age=age; return this; } public UserBuilder address(String address){ this.address=address; return this; } public UserBuilder phone(String phone){ this.phone=phone; return this; } public User build(){ return new User(this); } } }
Ponto a ser notado:
O método de construção da classe User é privado, os chamadores não podem criar diretamente objetos User.
Os atributos da classe User são imutáveis. Todos os atributos têm o modificador final e são configurados com valores no método de construção. Além disso, são fornecidos apenas métodos getters para o exterior.
O método de construção da classe interna Builder aceita apenas os parâmetros obrigatórios e esses parâmetros obrigatórios são modificados com o modificador final.
Modo de chamada:
new User.UserBuilder("Jack","10086) .age(25) .address("GuangZhou") .phone("13800138000) .build();
Em comparação com os métodos de construtor e setter anteriores/Existem duas maneiras de usar métodos getter, o que melhora a legibilidade. O único problema possível é que pode ser gerado um número excessivo de objetos Builder, consumindo memória. No entanto, na maioria das vezes, a classe interna Builder usada é estática (static), então esse problema não é tão importante.
Sobre segurança de thread
O padrão Builder não é thread-safe. Se precisar verificar a validade de um parâmetro dentro da classe interna Builder, é necessário verificar após a criação do objeto.
正确示例:
public User build() { User user = new user(this); if (user.getAge() > 120) { throw new IllegalStateException("Age out of range"); // 线程安全 } return user; }
错误示例:
public User build() { if (age > 120) { throw new IllegalStateException("Age out of range"); // 非线程安全 } return new User(this); }
七、用到Builder模式的例子
1、Android中的AlertDialog.Builder
private void showDialog(){ AlertDialog.Builder builder=new AlertDialog.Builder(context); builder.setIcon(R.drawable.icon); builder.setTitle("Title"); builder.setMessage("Message"); builder.setPositiveButton("Button",1", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //TODO } }); builder.setNegativeButton("Button",2", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //TODO } }); builder.create().show(); }
2、OkHttp中OkHttpClient的创建
OkHttpClient okHttpClient = new OkHttpClient.Builder() .cache(getCache()) .addInterceptor(new HttpCacheInterceptor()) .addInterceptor(new LogInterceptor()) .addNetworkInterceptor(new HttpRequestInterceptor()) .build();
3、Retrofit中Retrofit对象的创建
Retrofit retrofit = new Retrofit.Builder() .client(createOkHttp()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(BASE_URL) .build();
Na prática, o papel do Director é omitido, e em muitos código-fonte de frameworks, quando se trata do padrão Builder, a maioria escolhe a versão mais simples.
Oitavo, vantagens e desvantagens
Vantagens:
Boa encapsulamento, que faz com que o cliente não precise saber os detalhes da implementação interna do produto
Independência do Builder e alta capacidade de expansão
Desvantagens:
Criação de objetos Builder e Director desnecessários, consumindo memória
Leitores interessados em mais conteúdo sobre Android podem consultar as seções especiais do site: 'Introdução e Aperfeiçoamento em Desenvolvimento de Android', 'Técnicas de Depuração e Solução de Problemas Comuns em Android', 'Resumo de Uso dos Componentes Básicos de Android', 'Resumo de Técnicas de View de Android', 'Resumo de Técnicas de Layout de Android' e 'Resumo de Uso dos Controles de Android'.
Espero que o conteúdo deste artigo ajude a todos a programar em Android.
Declaração: O conteúdo deste artigo é extraído da Internet, pertence ao autor original, foi contribuído e carregado pelos usuários da Internet, o site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidades legais relacionadas. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie um e-mail para: notice#w3Aviso: Quando enviar um e-mail para denúncia, substitua # por @ e forneça provas relevantes. Apenas após a verificação, o site deletará o conteúdo suspeito de violação de direitos autorais.