Патерн (шаблон) проектування prototype (прототип)
Призначення паттерна Prototype
Патерн Prototype (прототип) можна використовувати в наступних випадках:
Патерн Factory Method також робить систему незалежною від типів породжуваних об'єктів, але для цього він вводить паралельну ієрархію класів: для кожного типу створюваного об'єкта повинен бути присутнім відповідний клас-фабрика, що може бути небажано. Патерн Prototype позбавлений цього недоліку.
Опис паттерна Prototype
Для створення нових об'єктів патерн Prototype використовує прототипи. Прототип - це вже існуючий в системі об'єкт, який підтримує операцію клонування, тобто вміє створювати копію самого себе. Таким чином, для створення об'єкта деякого класу досить виконати операцію clone () відповідного прототипу.
Патерн Prototype реалізує подібну поведінку в такий спосіб: всі класи, об'єкти яких потрібно створювати, повинні бути підкласами одного загального абстрактного базового класу. Цей базовий клас повинен оголошувати інтерфейс методу clone (). Також тут можуть оголошуватися віртуальними і інші загальні методи, наприклад, initialize () в разі, якщо після клонування потрібна ініціалізація новоствореного об'єкта. Всі похідні класи повинні реалізовувати метод clone (). У мові С ++ для створення копій об'єктів використовується конструктор копіювання, однак, в загальному випадку, створення об'єктів за допомогою операції копіювання не є обов'язковим.
UML-діаграма класів паттерна Prototype

Для породження об'єкта деякого типу в системі повинен існувати його прототип. Прототип являє собою об'єкт того ж типу, єдиним призначенням якого є створення подібних йому об'єктів. Зазвичай для зручності всі існуючі в системі прототипи організовуються в спеціальні колекції-сховища або реєстри прототипів. Таке сховище може мати реалізацію у вигляді асоціативного масиву, кожен елемент якого являє пару "Ідентифікатор типу" - "Прототип". Реєстр прототипів дозволяє додавати або видаляти прототип, а також створювати об'єкт за ідентифікатором типу. Саме операції динамічного додавання і видалення прототипів в сховище забезпечують додаткову гнучкість системі, дозволяючи управляти процесом створення нових об'єктів.
Реалізація патерну Prototype
Наведемо реалізацію паттерна Prototype на прикладі побудови армій для військової стратегії "Пунічні війни". Детальний опис цієї гри можна знайти в розділі Що породжують патерни. Для спрощення демонстраційного коду будемо створювати військові персонажі для якоїсь абстрактної армії без урахування особливостей воюючих сторін.
Також як і для патерну Factory Method наведемо дві можливі реалізації паттерна Prototype, а саме:
- У вигляді узагальненого конструктора на основі прототипів, коли в полиморфном базовому класі Prototype визначається статичний метод, призначений для створення об'єктів. При цьому в якості параметра в цей метод повинен передаватися ідентифікатор типу створюваного об'єкта.
- На базі спеціально виділеного класу-фабрики.
Реалізація патерну Ptototype на основі узагальненого конструктора
У наведеній реалізації класи всіх створюваних військових одиниць, таких як лучники, піхотинці і кіннота, є підкласами абстрактного базового класу Warrior. В цьому класі визначено узагальнений конструктор у вигляді статичного методу createWarrior (Warrior_ID id). Передаючи в цей метод в якості параметра тип бойової одиниці, можна створювати воїнів потрібних родів військ. Для цього узагальнений конструктор використовує реєстр прототипів, реалізований у вигляді асоціативного масиву std :: map, кожен елемент якого являє собою пару "ідентифікатор типу воїна" - "його прототип".
Додавання прототипів до реєстру відбувається автоматично. Зроблено це в такий спосіб. У підкласах Infantryman, Archer, Horseman, прототипи визначаються у вигляді статичних членів даних тих же типів. При створенні такого прототипу буде викликатися конструктор з параметром типу Dummy, який і додасть цей прототип в реєстр прототипів за допомогою методу addPrototype () базового класу Warrior. Важливо, щоб до цього моменту сам об'єкт реєстру був повністю сконструйований, саме тому він виконаний у вигляді singleton Мейерс.
Для наведеної реалізації паттерна Prototype можна відзначити такі особливості:
- Створювати нових воїнів можна тільки за допомогою узагальненого конструктора. Їх безпосереднє створення неможливо, так як відповідні конструктори оголошені зі специфікатором доступу private.
- Відсутня недолік реалізації на базі узагальненого конструктора для патерну Factory Method. а саме базовий клас Warrior нічого не знає про своїх підкласах.
Реалізація патерну Prototype за допомогою виділеного класу-фабрики
У наведеній реалізації для спрощення коду реєстр прототипів не ведеться. Воїни всіх родів військ створюються за допомогою відповідних методів фабричного класу PrototypeFactory, де і визначено прототипи у вигляді статичних змінних.
Результати застосування патерну Prototype
Переваги паттерна Prototype
- Для створення нових об'єктів клієнту необов'язково знати їх конкретні класи.
- Можливість гнучкого управління процесом створення нових об'єктів за рахунок можливості динамічних додавання і видалення прототипів до реєстру.