Перейти к содержанию

Prototype.cs

Код подключён напрямую из исходного файла в кодировке UTF-8, поэтому эта страница всегда показывает его актуальную версию.

← К конспекту Скачать исходный файл

Prototype.cs
using System;
using System.Collections.Generic;

namespace DesignPatterns.Creational.Prototype
{
    public interface IPrototype<out T>
    {
        T Clone();
    }

    // Конкретный прототип сам копирует своё состояние, включая закрытые поля.
    public sealed class Document : IPrototype<Document>
    {
        private readonly List<string> _pages;

        public string Title { get; }
        public IReadOnlyList<string> Pages => _pages.AsReadOnly();

        public Document(string title, IEnumerable<string> pages)
        {
            Title = title;
            _pages = new List<string>(pages);
        }

        private Document(Document source)
        {
            Title = source.Title;
            // Глубокая копия изменяемой коллекции: клон не делит список с оригиналом.
            _pages = new List<string>(source._pages);
        }

        public Document Clone() => new(this);

        public void AddPage(string text) => _pages.Add(text);
    }

    // Необязательное хранилище заранее настроенных прототипов.
    public sealed class DocumentRegistry
    {
        private readonly Dictionary<string, Document> _prototypes = new();

        public void Register(string key, Document prototype) =>
            _prototypes[key] = prototype;

        public Document Create(string key) =>
            _prototypes.TryGetValue(key, out Document? prototype)
                ? prototype.Clone()
                : throw new KeyNotFoundException($"Прототип '{key}' не зарегистрирован.");
    }

    public static class Demo
    {
        public static void Run()
        {
            var registry = new DocumentRegistry();
            registry.Register("invoice", new Document(
                "Счёт",
                new[] { "Реквизиты", "Позиции", "Итого" }));

            Document first = registry.Create("invoice");
            Document second = registry.Create("invoice");
            first.AddPage("Комментарий для первого клиента");

            Console.WriteLine(first.Pages.Count);  // 4
            Console.WriteLine(second.Pages.Count); // 3: коллекция скопирована глубоко
        }
    }
}