
//Target
trait Text {
//Request()
fn get_text(&self) -> String;
}
//Adaptee
struct StringList<'a> {
rows: Vec<&'a str>
}
impl<'a> StringList<'a> {
//SpecificRequest()
fn get_string(&self) -> String {
self.rows.join("\n")
}
fn add(&mut self, value: &'a str) {
self.rows.push(value);
}
}
//Adapter
struct TextAdapter<'a> {
row_list: StringList<'a>
}
impl Text for TextAdapter<'_> {
//Request()
fn get_text(&self) -> String {
self.row_list.get_string()
}
}
fn get_text_adapter<'a>() -> TextAdapter<'a> {
let mut row_list = StringList { rows: vec![] };
row_list.add("line 1");
row_list.add("line 2");
let adapter = TextAdapter {
row_list: row_list };
adapter
}
//Client
let adapter = get_text_adapter();
let text = adapter.get_text();
//text: line 1
// line 2
println!("text:\n{text}");
Преобразует интерфейс класса в другой интерфейс, ожидаемый клиентами. Обеспечивает совместную работу классов, которая была бы невозможна без данного паттерна из-за несовместимости интерфейсов.Read moreЗадача. Программа читает текст из любого источника через один метод. Другая часть системы выдаёт готовые списки строк. Список умеет склеивать свои строки, но метод у него называется иначе. Списки приходят уже заполненными, и их класс изменить нельзя. Переписывать код, который вызывает ожидаемый метод, тоже не хочется. Идея. Адаптер подгоняет существующий класс под интерфейс, которого ждёт клиент. Такой класс называют адаптируемым, а нужный клиенту интерфейс - целевым. В этом варианте адаптер реализует целевой интерфейс и хранит ссылку на адаптируемый объект. Его целевой метод передаёт вызов этому объекту, иногда с небольшим преобразованием. Остальных методов адаптируемого у адаптера нет. Для сравнения: адаптер через наследование расширяет адаптируемый класс, а не хранит его объект. Как читать пример. Объектов здесь два: адаптируемый и адаптер, который его хранит. В большинстве языков адаптируемый объект создаётся отдельно и передаётся адаптеру. В немногих адаптер сам создаёт свой адаптируемый объект, а клиент наполняет его через поле адаптера. Результат клиент читает только через целевой метод, и адаптер передаёт этот вызов адаптируемому. Некоторые адаптеры возвращают пустой результат, если адаптируемого объекта у них нет. В некоторых языках адаптер - просто функция, которая захватывает адаптируемый объект. Когда применять. В большинстве случаев лучше адаптер объекта. Он подгонит любой объект адаптируемого типа, в том числе подклассы и уже существующие объекты. А если адаптируемый класс можно просто изменить, адаптер не нужен вовсе: переименовать один метод дешевле. Частая ошибка. Вкладывать в адаптер новую логику. Адаптер только переводит один вызов в другой. Проверкам и бизнес-правилам место не здесь. |