English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Эта статья пример讲述了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 (при отправке письма замените # на @) для жалоб, и предоставьте соответствующие доказательства. Если факт будет установлен, сайт немедленно удалят涉嫌侵权的内容。