Прототип (Prototype)

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск

К основной странице курса

Назначение

Облегчает динамическое создание путем определения классов, объекты которых могут создавать свои дубликаты.

Описание

Прототип - это объект, который может быть использован в качестве образца для создания точно такого же объекта с точно такими же значениями полей (клона). Более того: если в переменной типа Prototype хранится объект класса ConcretePrototype, то клонируется именно этот объект.

В стандартной библиотеке .NET имеется интерфейс ICloneable с единственным методом Clone(), предназначенном для этих целей. Реализация метода Clone() возлагается на класс. Однако, в классе Object есть protected-метод MemberwiseClone(), который выполняет неглубокое клонирование (клонирование подобъектов только первого уровня), что в большинстве случаев достаточно.

Использование

Паттерн Прототип используется когда:

  • Инстанцируемые классы определяются во время выполнения
  • Экземпляры класса могут находиться в одном из не очень большого числа состояний

Реализация

Диаграмма классов

PrototypeCommon.png

Участники

  • Prototype - прототип

Объявляет интерфейс клонирования

  • ConcretePrototype - конкретный прототип

Реализует интерфейс клонирования

  • Client - клиент

Создает новый объект с запросом к прототипу клонировать себя

Пример

Поскольку пример паттерна Прототип сам по себе простой. Поэтому ниже приводится пример с MazeGame, в котором абстрактная фабрика заменена на прототипную фабрику. Если абстрактная фабрика требует порождения подкласса фабрики для конструирования объектов других типов, то прототипная фабрика инициализируется объектами-прототипами. и ее подкласс создавать не нужно.

Код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MazeCommon;
using MazeGameAbstractFactory;
using MazeGame = MazeGameAbstractFactory.MazeGame;

namespace MazegamePrototype
{
    class MazePrototypeFactory: MazeFactory 
    {
        private Room prototypeRoom;
        private Wall prototypeWall;
        private Door prototypeDoor;

        public MazePrototypeFactory(Wall w, Room r, Door d) 
        {
	    prototypeWall = w;
	    prototypeRoom = r;
	    prototypeDoor = d;
	}
        
        public override Wall MakeWall()
	{ 
            return (Wall)prototypeWall.Clone(); 
        }
        
        public override Door MakeDoor(Room r1, Room r2) 
        { 
	    Door d = (Door)prototypeDoor.Clone();
	    d.Initialize(r1,r2);
	    return d;
	}
        
        public override Room MakeRoom(int n)
        {
            Room r = (Room)prototypeRoom.Clone();
            r.RoomNumber = n;
            return r;
        }
    }

    class ProgramPrototype
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Prototype");
            MazeGame game = new MazeGame();
            MazePrototypeFactory f = new MazePrototypeFactory(new Wall(),new Room(1),new Door());
            game.CreateMaze(f);
        }
    }
}

Достоинства и недостатки

  • Сокрытие истинного типа клонируемого объекта - гибкость для клиента
  • Недостаток: клонирование объекта при наличии круговых ссылок - достаточно сложная задача.

Варианты

  • Если число прототипов невелико, то можно вести реестр прототипов с помощью диспетчера прототипов (паттерн Пул объектов).
  • В некоторых случаях необходимо клонировать весь объект, в других, достаточно создать клон по типу объекта с полями, заполненными значениями по умолчанию.