Абстрактная фабрика – еще один очень популярный паттерн, который как и в названии так и в реализации слегка похож на фабричный метод.
Итак, что же делает абстрактная фабрика: Абстрактная фабрик дает простой интерфейс для создания объектов которые принадлежат к тому или иному сеймейству объектов.
Отличия от фабричного метода:
- Фабричный метод порождает объекты одного и того же типа, фабрика же может создавать независимые объекты.
- Чтобы добавить новый тип объекта – надо поменять интерфейс фабрики, в фабричном методе же легко просто поменять внутренности метода, который ответственный за порождение объектов.
Давайте представим ситуацию: у нас есть две фабрики по производству 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 и др.
Немає коментарів:
Дописати коментар