
//Target
@protocol IText <NSObject>
//Request()
- (NSString *)getText;
@end
//Adaptee
@interface StringList : NSObject
@property (nonatomic, strong) NSMutableArray<NSString *> *rows;
//SpecificRequest()
- (NSString *)getString;
- (void)add:(NSString *)value;
@end
@implementation StringList
- (instancetype)init {
self = [super init];
if (self) {
_rows = [NSMutableArray array];
}
return self;
}
- (NSString *)getString {
return [self.rows componentsJoinedByString:@"\n"];
}
- (void)add:(NSString *)value {
[self.rows addObject:value];
}
@end
//Adapter
@interface TextAdapter : NSObject <IText>
@property (nonatomic, strong) StringList *rowList;
@end
@implementation TextAdapter
//Request()
- (NSString *)getText {
if (self.rowList == nil) {
return @"";
}
return [self.rowList getString];
}
@end
TextAdapter *getTextAdapter(void) {
TextAdapter *adapter = [[TextAdapter alloc] init];
StringList *rowList = [[StringList alloc] init];
[rowList add:@"line 1"];
[rowList add:@"line 2"];
adapter.rowList = rowList;
return adapter;
}
//Client
TextAdapter *adapter = getTextAdapter();
NSString *text = [adapter getText];
//text: line 1
// line 2
NSLog(@"text is \"%@\"", text);
Преобразует интерфейс класса в другой интерфейс, ожидаемый клиентами. Обеспечивает совместную работу классов, которая была бы невозможна без данного паттерна из-за несовместимости интерфейсов.Read moreЗадача. Программа читает текст из любого источника через один метод. Другая часть системы выдаёт готовые списки строк. Список умеет склеивать свои строки, но метод у него называется иначе. Списки приходят уже заполненными, и их класс изменить нельзя. Переписывать код, который вызывает ожидаемый метод, тоже не хочется. Идея. Адаптер подгоняет существующий класс под интерфейс, которого ждёт клиент. Такой класс называют адаптируемым, а нужный клиенту интерфейс - целевым. В этом варианте адаптер реализует целевой интерфейс и хранит ссылку на адаптируемый объект. Его целевой метод передаёт вызов этому объекту, иногда с небольшим преобразованием. Остальных методов адаптируемого у адаптера нет. Для сравнения: адаптер через наследование расширяет адаптируемый класс, а не хранит его объект. Как читать пример. Объектов здесь два: адаптируемый и адаптер, который его хранит. В большинстве языков адаптируемый объект создаётся отдельно и передаётся адаптеру. В немногих адаптер сам создаёт свой адаптируемый объект, а клиент наполняет его через поле адаптера. Результат клиент читает только через целевой метод, и адаптер передаёт этот вызов адаптируемому. Некоторые адаптеры возвращают пустой результат, если адаптируемого объекта у них нет. В некоторых языках адаптер - просто функция, которая захватывает адаптируемый объект. Когда применять. В большинстве случаев лучше адаптер объекта. Он подгонит любой объект адаптируемого типа, в том числе подклассы и уже существующие объекты. А если адаптируемый класс можно просто изменить, адаптер не нужен вовсе: переименовать один метод дешевле. Частая ошибка. Вкладывать в адаптер новую логику. Адаптер только переводит один вызов в другой. Проверкам и бизнес-правилам место не здесь. |