Прототип – один из самых простых паттернов, который позволяет нам получить точную копию необходимого объекта. То есть использовать как прототип для нового объекта.
Когда использовать:
- У нас есть семейство схожих объектов, разница между которыми только в состоянии их полей.
- Чтобы создать объект вам надо пройти через огонь, воду и медные трубы. Особенно если этот объект состоит из еще одной кучи объектов, многие из которых для заполнения требуют подгрузку даных из базы, веб сервисов и тому подобных источников. Часто, легче скопировать объект и поменять несколько полей.
- Да и в принципе, нам особо и не важно как создается объект. Ну есть и есть.
- Нам страшно лень писать иерархию фабрик (читайте дальше), которые будут инкапсулировать всю противную работу создания объекта.
Да, и есть еще частое заблуждение (вероятнее всего из названия) – прототип – это архитип, которые никогда не должен использоваться, и служит только для создания себе подобных объектов. Хотя, протип, как архитип – тоже достаточно популярный кейс. Собственно, нам ничего не мешает делать прототипом любой объект который у нас в подчинении.
Поверхностное и глубокое копирование
Тут особенно разницы с .NET нету. Есть указатель, есть значение в куче.
Поверхностное копирование – это просто создание нового указателя на те же самые байты в куче. То есть, в результате мы можем получить два объекта, которые указывают на одно и тоже значение.
К примеру создадим объект:
@interface ASPerson : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *surname; @property (nonatomic, copy) NSString *age; @end
А теперь давайте просто создадим два объекта и посмотрим что же получится:
ASPerson *firstPerson = [[ASPerson alloc] init]; firstPerson.name = @"Dima"; firstPerson.surname = @"Surname"; ASPerson *secondPerson = firstPerson; NSLog(@"First Person name = %@ and surname = %@", firstPerson.name, firstPerson.surname); secondPerson.name = @"Roma"; NSLog(@"Second Person name = %@ and surname = %@", secondPerson.name, secondPerson.surname); NSLog(@"First Person name = %@ and surname = %@", firstPerson.name, firstPerson.surname);
Как видим лог достаточно ожидаемый:
2017-06-18 22:33:52.234 PatternsObjC[1177:55666] First Person name = Dima and surname = Surname 2017-06-18 22:33:52.234 PatternsObjC[1177:55666] Second Person name = Roma and surname = Surname 2017-06-18 22:33:52.235 PatternsObjC[1177:55666] First Person name = Roma and surname = Surname
Заметьте, что хоть и меняли мы имя для secondPerson, но и у firstPerson имя поменялось. Просто потому что мы создали два указателя на один и тот же объект.
Для таких задач, стоит использовать глубокое копирование, которое в Objective-C сделанно в принципе очень похоже как и в .NET:
Для этого надо реализовать протокол NSCopying, и перегрузить:
- (id)copyWithZone:(nullable NSZone *)zone;
И да, не стоит переживать что мы не реализуем метод “copy”. Он уже есть у класса NSObject. Если вызвать этот метод, и не реализовать copyWithZone – то мы получем ошибку типа NSInvalidArgumentException.
Потому интерфейс нашего объекта теперь будет выглядеть следующим образом:
@interface ASPerson : NSObject <NSCopying> @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *surname; @property (nonatomic, copy) NSString *age; @end
а сама реализация:
@implementation ASPerson #pragma mark - NSCopying - (id)copyWithZone:(NSZone *)zone { ASPerson *copy = [[self class] allocWithZone:zone]; copy.name = self.name; copy.surname = self.surname; copy.age = self.age; return copy; } @end
Теперь немного изменим код нашего тестового приложения:
ASPerson *firstPerson = [[ASPerson alloc] init]; firstPerson.name = @"Dima"; firstPerson.surname = @"Surname"; ASPerson *secondPerson = firstPerson.copy; NSLog(@"First Person name = %@ and surname = %@", firstPerson.name, firstPerson.surname); secondPerson.name = @"Roma"; NSLog(@"Second Person name = %@ and surname = %@", secondPerson.name, secondPerson.surname); NSLog(@"First Person name = %@ and surname = %@", firstPerson.name, firstPerson.surname);
Ну, и естественно лог:
2017-06-18 22:47:01.577 PatternsObjC[1629:88078] First Person name = Dima and surname = Surname 2017-06-18 22:47:01.577 PatternsObjC[1629:88078] Second Person name = Roma and surname = Surname 2017-06-18 22:47:01.578 PatternsObjC[1629:88078] First Person name = Dima and surname = Surname
Как видим, мы в результате получили два независимых объекта, один из которых сделан по подобию первого.
Немає коментарів:
Дописати коментар