— Привіт, Аміго! Сьогодні я розповім тобі трохи цікавих речей про клас BufferedInputStream, але почнемо ми з «обгортки» та «мішка цукру ».
— Це що ще за «обгортка» та «мішок цукру»?
— Це – метафори. Слухай. Отже…
Паттерн проектування обгортка (Wrapper або Decorator) – це досить простий і зручний механізм розширення функціональності об'єктів.
Нехай у нас є клас Cat з двома методами getName та setName:
Код на Java | Опис |
---|---|
|
Клас Кіт має два методи: getName & setName |
|
Приклад використання.
У консоль буде виведено рядок «Васька». |
Припустимо, нам потрібно перехопити виклик методів у об'єкта cat і, можливо, внести туди невеликі зміни. Для цього нам знадобиться повернути його у свій клас-обгортку.
Якщо ми хочемо обернути виклики методів якогось об'єкта своїм кодом, то нам потрібно:
1) Створити свій клас-обгортку та успадкуватися від класу/інтерфейсу, для якого робимо обгортку.
2) Передати об'єкт, що обертається, у конструктор нашого класу.
3) Перевизначити всі методи в нашому новому класі та викликати в них методи об'єкта, що обертається.
4) Внести свої зміни до смаку: змінювати результати дзвінків, параметри або робити щось ще.
У прикладі нижче ми перехоплюємо виклик методу getName у об'єкта cat і трохи змінюємо його результат.
Код на Java | Опис |
---|---|
|
Клас Кот містить два методи – отримати ім'я та встановити ім'я. |
|
Клас-обгортка. Клас не зберігає жодних даних, крім посилання на оригінальний об'єкт. Клас може «прокидати» виклики оригінальному об'єкту (setName), переданому йому в конструкторі. А також «перехоплювати» ці виклики та модифікувати їх параметри та результати. |
|
Приклад використання.
У консоль буде виведено рядок |
Тобто. ми тихенько підмінюємо кожен оригінальний об'єкт на об'єкт-обертку, в який вже передаємо посилання на оригінальний об'єкт. Всі виклики методів обгортки йдуть до оригінального об'єкта, і все працює як годинник.
— Мені сподобалося. Рішення нескладне та функціональне.
— Ще я розповім тобі про «мішок цукру», але це не патерн, а метафора. Метафора до слова буфер і буферизація. Що ж таке буферизація і для чого вона потрібна?
Припустимо, сьогодні чергу Ріші готувати, а ти йому допомагаєш. Ріші ще немає, а я хочу випити чай і прошу тебе принести мені ложечку цукру. Ти пішов у підвал, там стоїть мішок із цукром. Ти можеш принести мені цілий мішок, але мішок мені не потрібний. Мені потрібна лише одна ложка. Тоді ти, як добрий робот, набрав одну ложку і приніс мені. Я додала її до чаю, але все одно не дуже солодко. І я попросила ще одну. Ти знову сходив у підвал і приніс ложку. Потім прийшла Еллі, і я попросила тебе принести цукру для неї… Це все надто довго та неефективно.
Прийшов Ріша, подивився на все це і попросив тебе принести йому повну цукорницю цукру. Потім я та Еллі стали просити цукор у Ріші. Він просто давав його нам із цукорниці, і все.
Те, що сталося після появи Ріші називається буферизацією, а цукорниця – це буфер. Завдяки буферизації «клієнти» можуть читати дані з буфера маленькими порціями, а буфер, щоб заощадити час і сили, читає їх із джерела великими порціями.
— Класний приклад, Кім. Я все зрозумів. Прохання ложки цукру – це аналог читання із потоку одного байта.
— Так. Клас BufferedInputStream – класичний представник обгортки-буфера. Він – клас-обгортка над InputStream. При читанні даних з нього він читає їх з оригінального InputStream'а великими порціями в буфер, а потім віддає з буфера потихеньку.
— Чудово. Все зрозуміло. А буфери для запису бувають?
— Так, звичайно.
— А чи можна приклад?
— Уяви собі відро для сміття. Замість того, щоб щоразу ходити викидати сміття на вулиці в дезінтегратор, ти просто викидаєш його у відро для сміття. А Скрафі раз на два тижні виносить його надвір. Класичний буфер.
— Як цікаво. І набагато зрозуміліше, до речі, ніж із мішком цукру.
— А метод flush() – це винести сміття негайно. Можна використовувати перед відвідуванням гостей.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ