English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Пример реализации模式的 Builder в Android (подробное объяснение)

Эта статья пример讲述了Android programming design pattern Builder. Предоставляется для обсуждения, подробности см. ниже:

Один. Обзор

Шаблон Builder - это шаблон создания сложного объекта, который позволяет пользователю контролировать процесс создания объекта более детально, не зная внутренних деталей создания. Этот шаблон предназначен для декомпозиции процесса создания сложного объекта и его компонентов, чтобы отделить процесс создания и представление компонентов.

Поскольку сложный объект имеет множество компонентов, например, автомобиль имеет колеса, рулевое управление, двигатель и различные мелкие детали и т.д., как собрать эти компоненты в автомобиль, этот процесс очень долгий и сложен. В таких случаях, чтобы скрыть реализационные детали от внешнего мира в процессе создания, можно использовать шаблон Builder, чтобы отделить компоненты и процесс сборки, что позволяет свободно расширять процесс создания и компоненты, а также降到最低耦合.

Два. Определение

Отделение процесса создания сложного объекта от его представления, чтобы один и тот же процесс создания мог создавать различные представления.

Три. Сценарии использования

(1) Когда одни и те же методы, различный порядок выполнения приводят к различным результатам событий.

(2) Множество компонентов или деталей могут быть собраны в один объект, но результаты выполнения не всегда одинаковы.

(3) Класс продукта очень сложен, или различный порядок вызова в классе продукта produces different effects, then using the Builder pattern is very appropriate.

(4) Когда инициализация объекта особенно сложна, например, множество параметров, и многие параметры имеют значения по умолчанию.

Четыре. UML-диаграмма класса模式的 Builder

Объяснение ролей:

Product класс продукта - абстрактный класс продукта;

Builder - абстрактный класс Builder, который нормализует создание продукта, обычно реализует конкретный процесс создания подклассами;

ConcreateBuilder - конкретный класс Builder;

Director - унификация процесса сборки;

Пять. Простейшее реализация模式的 Builder

Процесс сборки компьютера относительно сложен и последовательность сборки не фиксирована. Для удобства понимания мы упрощаем процесс сборки компьютера до трех частей: строительство системного блока, настройка операционной системы и настройка монитора, а затем строим объект компьютера через Director и конкретного Builder.

Пример кода:

/**
 * Абстрактный класс компьютера, то есть роль Product
 */
public abstract class Computer {
  protected String mBoard;
  protected String mDisplay;
  protected String mOS;
  protected Computer(){}
  /**
   * Установить материнскую плату
   * @param board
   */
  public void setBoard(String board){
    this.mBoard = board;
  }
  /**
   * Установить монитор
   * @param display
   */
  public void setDisplay(String display){
    this.mDisplay = display;
  }
  /**
   * Установить операционную систему
   */
  public abstract void setOS();
  @Override
  public String toString(){
    return "Computer [mBoard=" + mBoard + ", mDisplay=" + mDisplay + ", mOS=" + mOS + "]";
  }
}
/**
 * Специализированный класс Computer, Macbook
 */
public class Macbook extends Computer {
  protected Macbook(){}
  @Override
  public void setOS() {
    mOS = "Mac OS X 10";
  }
}
/**
 * Абстрактный класс Builder
 */
public abstract class Builder {
  /**
   * Установить материнскую плату
   * @param board
   */
  public abstract void buildBoard(String board);
  /**
   * Установить монитор
   * @param display
   */
  public abstract void buildDisplay(String display);
  /**
   * Установить операционную систему
   */
  public abstract void buildOS();
  /**
   * Создание Computer
   * @return
   */
  public abstract Computer create();
}
/**
 * Специализированный класс Builder, 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, отвечает за строительство Computer
 */
public class Director {
  Builder mBuilder = null;
  public Director(Builder builder){
    mBuilder = builder;
  }
  /**
   * Строительство объекта
   * @param board Плата
   * @param display Дисплей
   */
  public void construct(String board, String display){
    mBuilder.buildBoard(board);
    mBuilder.buildDisplay(display);
    mBuilder.buildOS();
  }
}
/**
 * Тестовый код
 */
public class Test {
  public static void main(String[] args){
    //Конструктор
    Builder builder = new MacbookBuilder();
    //Director
    Director pcDirector = new Director(builder);
    //Закупорка процесса строительства
    pcDirector.construct("интеллектуальная плата","дисплей Retina");
    //Строительство компьютера, вывод相关信息
    System.out.println("Информация о компьютере: " + builder.create().toString());
  }
}

Результат вывода:

Информация о компьютере: Компьютер [mBoard=интеллектуальная плата, mDisplay=дисплей Retina, mOS=Mac OS X 10]

В данном примере, через конкретный MacbookBuilder строят объект Macbook, а Director скрывает детали процесса строительства сложных объектов. Builder вместе с Director отделяет строительство сложного объекта от его представления, что позволяет создавать различные объекты одним и тем же процессом строительства.

Стоит отметить, что в реальном разработке роль Director часто упускается. Вместо этого напрямую используется Builder для组装 объектов, который обычно выполняет цепную команду, ключевой момент которой — каждый метод setter возвращает само себя, то есть return this, что позволяет методам setter выполнять цепную команду. Пример кода примерно такой: }}

new TestBuilder()
  .setA("A")
  .create();

Таким образом, не только удаляется роль Director, но и вся структура становится более простой, и также обеспечивается более тонкий контроль над процессом组装 объекта Product.

Шестой вариант использования шаблона Builder — цепная вызов

Пример кода:

public class User {
  private final String name;     //required
  private final String cardID;    //required
  private final int age;       //optional
  private final String address;   //optional
  private final String phone;    //optional
  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);
    }
  }
}

Важно отметить:

Конструктор класса User является частным, вызов者和 не могут напрямую создавать объект User.

Атрибуты класса User не изменяются. Все атрибуты помечены ключевым словом final и устанавливаются значением в конструкторе. Имеются только методы getters для доступа извне.

Конструктор внутреннего класса Builder принимает только необходимые параметры, и эти необходимые параметры помечены ключевым словом final.

Способ вызова:

new User.UserBuilder("Jack","10086")
    .age(25)
    .address("GuangZhou")
    .phone("13800138000")
    .build();

По сравнению с предыдущими способами через конструктор и методы setter/getter, они более читаемы. Единственная возможная проблема может заключаться в создании избыточных объектов Builder, что может потреблять память. Однако в большинстве случаев наш внутренний класс Builder является статическим (static), поэтому эта проблема не так важна.

О безопасности на уровне потока

Модель Builder не является безопасной в等多нитековых средах, если необходимо проверить легитимность параметра внутри класса Builder, это необходимо сделать после завершения создания объекта.

Правильный пример:

public User build() {
 User user = new user(this);
 if (user.getAge() > 120) {
  throw new IllegalStateException("Возраст вне диапазона"); // Безопасность на уровне потока
 }
 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("Button1", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
        //TODO
      }
    });
    builder.setNegativeButton("Button2", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
        //TODO
      }
    });
    builder.create().show();
}

2、OkHttpClient的创建在OkHttp中

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();

На практике, роль Director часто опускается, и когда в исходных кодах многих фреймворков встречается модель Builder, они часто выбирают более простую структуру, чем классический Builder GOF.

Восьмой раздел: достоинства и недостатки

Преимущества:

Хорошая упаковка, которая позволяет клиенту не знать подробности внутреннего выполнения продукта

Инструмент Builder независим и обладает сильной способностью к расширению

Недостатки:

Создание избыточных объектов Builder и Director, потребление памяти

Для читателей, интересующихся дополнительной информацией о Android, можно посмотреть专题文章 на нашем сайте: «Введение в разработку Android и продвинутые учебники», «Советы по отладке и методы решения часто встречающихся проблем в Android», «Обзор использования основных компонентов Android», «Обзор приемов работы с Android View и layout», «Обзор приемов работы с Android控件» и «Обзор методов использования Android компонент»

Надеюсь, что изложенное в этой статье поможет вам в разработке приложений для Android.

Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору, содержимое предоставлено пользователями Интернета в порядке самостоятельного的贡献 и загрузки, сайт не обладает правами собственности, не производилось ручное редактирование, и не несет ответственности за связанные с этим юридические последствия. Если вы обнаружите контент,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма замените # на @) для жалоб, и предоставьте соответствующие доказательства. Если факт будет установлен, сайт немедленно удалят涉嫌侵权的内容。

Основной учебник
Рекомендуется к просмотру