Абстрактная фабрика – еще один очень популярный паттерн, который как и в названии так и в реализации слегка похож на фабричный метод.
Итак, что же делает абстрактная фабрика: Абстрактная фабрик дает простой интерфейс для создания объектов которые принадлежат к тому или иному сеймейству объектов.
Отличия от фабричного метода:
- Фабричный метод порождает объекты одного и того же типа, фабрика же может создавать независимые объекты.
- Чтобы добавить новый тип объекта – надо поменять интерфейс фабрики, в фабричном методе же легко просто поменять внутренности метода, который ответственный за порождение объектов.
Давайте представим ситуацию: у нас есть две фабрики по производству iPhone и iPad. Одна оригинальная, компании Apple, другая – хижина дядюшки Хуа. И вот, мы хотим производить эти товары: если в страны 3-го мира – то товар от дядюшки, в другие страны – товар любезно предоставлен компанией Apple.
Итак, пускай у нас есть фабрика, которая умеет производить и айпады и айфоны:
@class ASGenericIPhone, ASGenericIPad; @interface ASIPhoneFactory : NSObject - (ASGenericIPhone *)iPhone; - (ASGenericIPad *)iPad; @end
Естественно, нам необходимо реализовать продукты которые фабрика будет производить:
@interface ASGenericIPad : NSObject @property (nonatomic, copy) NSString *osName; @property (nonatomic, copy) NSString *productName; @property (nonatomic, strong) NSNumber *screenSize; @end
@interface ASGenericIPhone : NSObject @property (nonatomic, copy) NSString *osName; @property (nonatomic, copy) NSString *productName; @end
Но, продукты немного отличаются.
Пускай у нас есть два типа продуктов, оригинальные Apple и продукты которые произведены трутолюбивым дядюшкой Хуа:
@interface ASAppleIPad : ASGenericIPad @end
@implementation ASAppleIPad
- (instancetype)init {
self = [super init];
if (self) {
self.productName = @"iPad";
self.osName = @"iOS";
self.screenSize = @9.7;
}
return self;
}
@end
@interface ASAppleIPhone : ASGenericIPhone @end
@implementation ASAppleIPhone
- (instancetype)init {
self = [super init];
if (self) {
self.productName = @"iPhone";
self.osName = @"iOS";
}
return self;
}
@end
Дядюшкофоны:
@interface ASChinaPad : ASGenericIPad @end
@implementation ASChinaPad
- (instancetype)init {
self = [super init];
if (self) {
self.productName = @"Buan Que Ipado Killa";
self.osName = @"Windows CE";
self.screenSize = @12.5;
}
return self;
}
@end
@interface ASChinaPhone : ASGenericIPhone @end
@implementation ASChinaPhone
- (instancetype)init {
self = [super init];
if (self) {
self.productName = @"Chi Huan Hua Phone";
self.osName = @"Android";
}
return self;
}
@end
Разные телефоны, конечно же, производятся на различных фабриках, потому мы просто обязанны их создать! Приблизительно так должны выглядеть фабрика Apple:
@interface ASAppleFactory : ASIPhoneFactory
#import "ASAppleIPad.h"
#import "ASAppleIPhone.h"
@implementation ASAppleFactory
- (ASGenericIPad *)iPad {
return [ASAppleIPad new];
}
- (ASGenericIPhone *)iPhone {
return [ASAppleIPhone new];
}
Конечно же у нашего китайского дядюшки тоже есть своя фабрика:
@interface ASChinaFactory : ASIPhoneFactory @end
#import "ASChinaPad.h"
#import "ASChinaPhone.h"
@implementation ASChinaFactory
- (ASGenericIPad *)iPad {
return [ASChinaPad new];
}
- (ASGenericIPhone *)iPhone {
return [ASChinaPhone new];
}
@end
Как видим, фабрики одинаковые, а вот девайсы у них получются разные ![]()
Вот собственно и все, мы приготовили все что надо для доменострации! Теперь, давайте напишем небольшой метод который будет возвращать нам фабрику которую мы хотим (кстати, тут фабричный метод таки будет):
- (ASIPhoneFactory *)factory {
return self.isThirdWorld ? [ASChinaFactory new] : [ASAppleFactory new];
}
Теперь, давайте как создадим несколько телефонов:
self.isThirdWorld = YES;
ASIPhoneFactory *factory = self.factory;
ASGenericIPad *ipad = factory.iPad;
ASGenericIPhone *iphone = factory.iPhone;
NSLog(@"iPad named = %@, osname = %@, screensize = %.1f",
ipad.productName, ipad.osName, ipad.screenSize.doubleValue);
NSLog(@"iPhone named = %@, osname = %@", iphone.productName, iphone.osName);
Лог будет выглядить следующим образом:
2017-06-20 21:47:34.670 PatternsObjC[1210:44956] iPad named = Buan Que Ipado Killa, osname = Windows CE, screensize = 12.5 2017-06-20 21:47:34.671 PatternsObjC[1210:44956] iPhone named = Chi Huan Hua Phone, osname = Android
Теперь, просто поменяв значение проперти isThirdWorld на NO, и лог будет совсем другой:
2017-06-20 21:44:55.887 PatternsObjC[1167:38662] iPad named = iPad, osname = iOS, screensize = 9.7 2017-06-20 21:44:55.888 PatternsObjC[1167:38662] iPhone named = iPhone, osname = iOS
Пример Abstract Factory в Foundation, iOS SDK - классы NSNumber, NSData, NSArray, NSDictionary, NSString. Рассмотрим на примере NSNumber, эта фабрика возвращает такие классы - NSCFNumber, NSCFBoolean и др.
Немає коментарів:
Дописати коментар