понеділок, 19 червня 2017 р.

Factory Method

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

Когда использовать:

  1. Мы не до конца уверены объект какого типа нам необходим.
  2. Мы хотим чтобы не родительский объект решал какой тип создавать, а его наследники.

Почему хорошо использовать:

Объекты созданные фабричным методом – схожи, потому как у них один и тот же родительский объект. Потому, если локализировать создание таких объектов, то можно добавлять новые типы, не меняя при это код который использует фабричный метод.

Пример:

Давайте представим, что мы такой неправильный магазин в котором тип товара оценивается по цене:) На данный момент товар есть 2-х типов – Игрушки и Одежда.

В чеке мы получаем только цены, и нам надо сохранить объекты которые куплены.

Для начала создадим класс ASProduct. Его реализация нас особо не интересует, хотя он может содержать в себе общие для разных типов товаров методы (сделано для примера, мы их особо не используем):

@interface ASProduct : NSObject

@property (nonatomic) NSInteger price;
@property (nonatomic, copy) NSString *name;

- (NSInteger)totalPriceWithSum:(NSInteger)sum;

- (void)saveObject;

@end
@implementation ASProduct

- (NSInteger)totalPriceWithSum:(NSInteger)sum {
    return self.price + sum;
}

- (void)saveObject {
    NSLog(@"I am saving an object in to product database");
}

@end

Теперь создадим две реализации этого интерфейса.

Игрушка:

@interface ASToy : ASProduct

@end
@implementation ASToy

- (void)saveObject {
    NSLog(@"Saving object into Toys database");
}

@end

И одежда:

@interface ASDress : ASProduct

@end
@implementation ASDress

- (void)saveObject {
    NSLog(@"Saving object into Dress database");
}

@end

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

@class ASProduct;

@interface ASProductGenerator : NSObject

- (ASProduct *)productByPrice:(NSInteger)price;

@end
#import "ASProductGenerator.h"

#import "ASToy.h"
#import "ASDress.h"

@implementation ASProductGenerator

- (ASProduct *)productByPrice:(NSInteger)price {
    
    if (price > 0 && price < 100) {
        return [ASToy new];
    }
    
    if (price >= 100) {
        return [ASDress new];
    }
    
    return nil;
}

@end

Вот собственно и все. Теперь просто создадим метод, который будет считать и записывать расходы:

- (void)saveExpenses:(NSInteger)price {
    ASProductGenerator *generator = [ASProductGenerator new];
    
    ASProduct *expense = [generator productByPrice:price];
    [expense saveObject];
}

Попробуем!

    [self saveExpenses:50];
    [self saveExpenses:56];
    [self saveExpenses:79];
    [self saveExpenses:100];
    [self saveExpenses:123];
    [self saveExpenses:51];

Лог:

2017-06-19 20:42:12.065 PatternsObjC[939:34445] Saving object into Toys database
2017-06-19 20:42:12.066 PatternsObjC[939:34445] Saving object into Toys database
2017-06-19 20:42:12.067 PatternsObjC[939:34445] Saving object into Toys database
2017-06-19 20:42:12.068 PatternsObjC[939:34445] Saving object into Dress database
2017-06-19 20:42:12.068 PatternsObjC[939:34445] Saving object into Dress database
2017-06-19 20:42:12.070 PatternsObjC[939:34445] Saving object into Toys database

Пример Factory Method в Foundation, iOS SDK - в классе NSNumber это методы:

- (NSNumber *)initWithChar:(char)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedChar:(unsigned char)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithShort:(short)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedShort:(unsigned short)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithInt:(int)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedInt:(unsigned int)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithLong:(long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedLong:(unsigned long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithLongLong:(long long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedLongLong:(unsigned long long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithFloat:(float)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithDouble:(double)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithBool:(BOOL)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithInteger:(NSInteger)value NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedInteger:(NSUInteger)value NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;

Немає коментарів:

Дописати коментар

HyperComments for Blogger

comments powered by HyperComments