Вот представьте что у нас есть фабрика. Но в отличии от фабрики из предыдущего поста, она умеет создавать только телефоны на базе андроида, и еще при этом различной конфигурации. То есть, есть один объект, но при этом его состояние может быть совершенно разным, а еще представьте если его очень трудно создавать, и во время создания этого объекта еще и создается миллион дочерних объектов. Именно в такие моменты, нам очень помогает такой паттерн как строитель.
Когда использовать:
- Создание сложного объекта.
- Процесс создания объекта тоже очень не тривиальный – к примеру получение данных из базы и манипуляция ими.
Сам паттерн состоит из двух компонент – Bulilder и Director. Builder занимается именно построением объекта, а Director знает какой Builder использовать чтобы выдать необходимый продукт. Приступим!
Пускай у нас есть телефон, который обладает следующими свойствами:
@interface ASAndroidPhone : NSObject @property (nonatomic, copy) NSString *osVersion; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *cpuCodeName; @property (nonatomic, strong) NSNumber *RAMsize; @property (nonatomic, strong) NSNumber *osVersionCode; @property (nonatomic, copy) NSString *launcher; @end
Давайте создадим дженерик строителя от которого будут наследоваться конкретные строители:
@class ASAndroidPhone; @interface ASAndroidPhoneBuilder : NSObject @property (nonatomic, strong, readonly) ASAndroidPhone *phone; - (void)setOSVersion; - (void)setName; - (void)setCPUCodeName; - (void)setRAMSize; - (void)setOSVersionCode; - (void)setLauncher; @end
#import "ASAndroidPhone.h"
@interface ASAndroidPhoneBuilder ()
@property (nonatomic, strong) ASAndroidPhone *phone;
@end
@implementation ASAndroidPhoneBuilder
- (instancetype)init {
self = [super init];
if (self) {
_phone = [ASAndroidPhone new];
}
return self;
}
- (void)setOSVersion {
}
- (void)setName {
}
- (void)setCPUCodeName {
}
- (void)setRAMSize {
}
- (void)setOSVersionCode {
}
- (void)setLauncher {
}
@end
А теперь напишем код для конкретных строителий. К примеру, так бы выглядел строитель для дешевого телефона:
@interface ASLowPricePhoneBuilder : ASAndroidPhoneBuilder
#import "ASAndroidPhone.h"
@implementation ASLowPricePhoneBuilder
- (void)setOSVersion {
self.phone.osVersion = @"Android 2.3";
}
- (void)setName {
self.phone.name = @"Low price phone!";
}
- (void)setCPUCodeName {
self.phone.cpuCodeName = @"Some shitty CPU";
}
- (void)setRAMSize {
self.phone.RAMsize = @256;
}
- (void)setOSVersionCode {
self.phone.osVersionCode = @3.0;
}
- (void)setLauncher {
self.phone.launcher = @"Hia Tsung!";
}
@end
И конечно же строительство дорогого телефона:
@interface ASHighPricePhoneBuilder : ASAndroidPhoneBuilder @end
#import "ASAndroidPhone.h"
@implementation ASHighPricePhoneBuilder
- (void)setOSVersion {
self.phone.osVersion = @"Android 7.1";
}
- (void)setName {
self.phone.name = @"High price phone!";
}
- (void)setCPUCodeName {
self.phone.cpuCodeName = @"Some shitty but expensive CPU";
}
- (void)setRAMSize {
self.phone.RAMsize = @6144;
}
- (void)setOSVersionCode {
self.phone.osVersionCode = @7.1;
}
- (void)setLauncher {
self.phone.launcher = @"Samsung Launcher!";
}
@end
Кто-то же должен использовать строителей, потому давайте создадим объект который будет с помощью строителей создавать дешевые или дорогие телефоны:
@class ASAndroidPhone, ASAndroidPhoneBuilder; @interface ASFactorySalesMan : NSObject - (void)setBuilder:(ASAndroidPhoneBuilder *)builder; - (ASAndroidPhone *)phone; - (void)constructPhone; @end
#import "ASAndroidPhone.h"
#import "ASAndroidPhoneBuilder.h"
@interface ASFactorySalesMan ()
@property (nonatomic, strong) ASAndroidPhoneBuilder *builder;
@end
@implementation ASFactorySalesMan
- (ASAndroidPhone *)phone {
return self.builder.phone;
}
- (void)constructPhone {
[self.builder setOSVersion];
[self.builder setName];
[self.builder setCPUCodeName];
[self.builder setRAMSize];
[self.builder setOSVersionCode];
[self.builder setLauncher];
}
Ну и конечно же куда мы без теста и кода:
ASLowPricePhoneBuilder *cheapPhoneBuilder = [ASLowPricePhoneBuilder new];
ASHighPricePhoneBuilder *expensivePhoneBuilder = [ASHighPricePhoneBuilder new];
ASFactorySalesMan *salesMan = [ASFactorySalesMan new];
[salesMan setBuilder:cheapPhoneBuilder];
[salesMan constructPhone];
ASAndroidPhone *phone = [salesMan phone];
NSLog(@"Phone Name = %@, osVersion = %@, cpu code name = %@, ram size = %@, os version code = %@, launcher = %@", phone.name, phone.osVersion, phone.cpuCodeName, phone.RAMsize, phone.osVersionCode, phone.launcher);
[salesMan setBuilder:expensivePhoneBuilder];
[salesMan constructPhone];
phone = [salesMan phone];
NSLog(@"Phone Name = %@, osVersion = %@, cpu code name = %@, ram size = %@, os version code = %@, launcher = %@", phone.name, phone.osVersion, phone.cpuCodeName, phone.RAMsize, phone.osVersionCode, phone.launcher);
Как видим, мы создали различных строителей, и сказав директору (ASFactorySalesMan) какой строитель мы хотим использовать, мы получаем тот девайс который нам необходим.
Традиционный лог:
2017-06-22 23:17:16.889 PatternsObjC[1207:41570] Phone Name = Low price phone!, osVersion = Android 2.3, cpu code name = Some shitty CPU, ram size = 256, os version code = 3, launcher = Hia Tsung! 2017-06-22 23:17:16.889 PatternsObjC[1207:41570] Phone Name = High price phone!, osVersion = Android 7.1, cpu code name = Some shitty but expensive CPU, ram size = 6144, os version code = 7.1, launcher = Samsung Launcher!
Пример Builder в Foundation, iOS SDK - классы NSURL, NSDate. Рассмотрим на примере NSURL.
NSURL *url = [NSURL URLWithBuilderBlock:^(NSURLComponents *builder) {
builder.scheme = @"http";
builder.host = @"programming086.blogspot.com";
builder.path = @"/2017/06/builder.html";
}];
Немає коментарів:
Дописати коментар