В этой статье рассматриваются дополнительные шаблоны, которые не входят в «Банду четырех», но используются при разработке приложений. К ним относятся такие шаблоны, как «Абстрактный документ», «Активный объект», «Ациклический посетитель», «Блокирование», «Байткод», «Кэширование», «Обратный вызов», «Асинхронный вызов метода», «Контекст объекта», «Конвертер». . , «Объект доступа к данным», «Объект передачи данных», «Грязный флаг», «Двойной буфер», «Очередь событий», «Выполнение вокруг», «Монада», «Моно-состояние», «Идиома отключения звука», «Голые объекты» «, «Нулевой объект», «Мать объекта», «Пул объектов», «Объект параметра» и многие другие.

Аннотация документа

Модель «Абстрактный документ» — это структурная модель, реализующая обработку иерархических и древовидных структур для документов разных типов. Он позволяет присваивать свойства объектам без их ведома.

Модель использует концепцию свойств для обеспечения безопасности типов и разделения свойств разных классов на наборы интерфейсов.

Аннотация документа

Суть в том, что вариативность документов достигается с помощью общего интерфейса, а иерархия достигается с помощью Dictionary<String, Object>. Результирующий объект содержит карту свойств и любое количество дочерних объектов.

Давайте определим общий интерфейс, а также базовую реализацию таких действий, как добавление пары «Строка-Объект», получение объекта по ключу и получение дочерних элементов.

Определить интерфейс и операции
public interface IDocument
{
    public void Put(string key, object value);

    public object Get(string key);

    public List<Dictionary<string, object>> Children(string key);
}

public abstract class AbstractDocument : IDocument
{
    protected Dictionary<string, object> Dictionary;

    protected AbstractDocument(Dictionary<string, object> keyValuePairs)
    {
        this.Dictionary = keyValuePairs;
    }

    public List<Dictionary<string, object>> Children(string key)
    {
        List<Dictionary<string, object>> results = new();

        if (Get(key) is not List<Dictionary<string, object>> childrens) 
        {
            return results;
        }

        foreach (Dictionary<string, object> children in childrens)
        {
            results.Add(children);
        }

        return results;
    }

    public object Get(string key)
    {
        return Dictionary[key];
    }

    public void Put(string key, object value)
    {
        Dictionary.Add(key, value);
    }
}

Давайте определим перечисление Property и набор интерфейсов для основных функций. Это позволит вам реализовать любой тип документа.

Определить перечисление и интерфейсы
public enum Property
{
    Parts, Chars, Rows, Colls, Type, Version
}

public interface IParts : IDocument
{
    public object GetParts();
}

public interface IChars : IDocument
{
    public int GetChars();
}

public interface IType : IDocument
{
    public string GetType();
}

public interface IRows : IDocument
{
    public int GetRows();
}

public interface IColls : IDocument
{
    public int GetColls();
}

public interface IVersion : IDocument
{
    public int GetVersion();
}

Давайте определим различные типы документов, используя AbstractDocument и интерфейсы, определенные выше.

ЧИТАТЬ   Как GPT Chat изменит мир | Объяснение GPT-чата (часть 2)
Определить реализацию документа
public class TextDocument : AbstractDocument, 
  IParts, IChars, IType, IVersion
{
    public TextDocument(Dictionary<string, object> keyValuePairs) 
      : base(keyValuePairs)
    {
        this.Dictionary = keyValuePairs;
    }

    public int GetChars()
    {
        return (int)this.Dictionary[Property.Chars.ToString()];
    }

    public object GetParts()
    {
        return this.Dictionary[Property.Parts.ToString()];
    }

    public int GetVersion()
    {
        return (int)this.Dictionary[Property.Version.ToString()];
    }

    public new string GetType()
    {
        return (string)this.Dictionary[Property.Type.ToString()];
    }
}

public class TableDocument : AbstractDocument, 
  IType, IRows, IColls, IVersion
{
    public TableDocument(Dictionary<string, object> keyValuePairs) 
      : base(keyValuePairs)
    {
        this.Dictionary = keyValuePairs;
    }

    public new string GetType()
    {
        return (string)this.Dictionary[Property.Type.ToString()];
    }

    public int GetRows()
    {
        return (int)this.Dictionary[Property.Rows.ToString()];
    }

    public int GetColls()
    {
        return (int)this.Dictionary[Property.Colls.ToString()];
    }

    public int GetVersion()
    {
        return (int)this.Dictionary[Property.Version.ToString()];
    }
}

Попробуем создать текстовый файл. Он содержит основные характеристики: тип, версию, количество символов, а также файл таблицы. Табличный файл имеет версию, тип, количество строк и столбцов.

Используйте шаблон
private static void Main(string[] args)
{
    Dictionary<string, object> tableDocumentProperties = new()
    {
        { Property.Version.ToString(), 1 },

        { Property.Rows.ToString(), 10 },

        { Property.Colls.ToString(), 5 },

        { Property.Type.ToString(), ".xslx" }
    };

    Dictionary<string, object> textDocumentProperties = new()
    {
        { Property.Version.ToString(), 1 },

        { Property.Chars.ToString(), 10000 },

        { Property.Type.ToString(), ".docx" },

        {
            Property.Parts.ToString(),
            new List<Dictionary<string, object>>() { tableDocumentProperties }
        }
    };

    TextDocument textDocument = new(textDocumentProperties);

    Console.WriteLine(textDocument.GetType());

    Console.WriteLine(textDocument.GetVersion());

    Console.WriteLine(textDocument.GetChars());

    var textDocumentParts = textDocument.GetParts() as List<Dictionary<string, object>>;

    foreach (var part in textDocumentParts)
    {
        foreach (var item in part.Keys)
        {
            Console.WriteLine(item + " " + part[item]);
        }
    }
}

Монада (Монада)

Модель Монада — это функциональная модель, которая гарантирует выполнение каждой операции независимо от успеха или неудачи предыдущей операции.

Примером является проверка, при которой каждый шаг выполняется с уверенностью в том, что предыдущие шаги выполнены.

Реализация модели
public class Validator<T>
{
    private readonly T value;
    private readonly List<Exception> errors = new List<Exception>();

    public Validator(T value)
    {
        this.value = value;
    }

    public Validator<T> Validate(Predicate<T> validation, string message)
    {
        if (!validation(value))
        {
            errors.Add(new Exception(message));
        }

        return this;
    }

    public (bool, List<string>) Get()
    {
        if (errors.Any())
        {
            List<string> result = new List<string>();

            foreach (Exception e in errors)
            {
                result.Add(e.Message);
            }

            return (false, result);
        }

        return (true, new List<string>());
    }
}

public record User(string Name, string Surname, string Fathername) { }

private static void Main(string[] args)
{
    User fio = new("Иван", "Иванович", "Иванов");

    Validator<User> validator = 
        new Validator<User>(fio)
        .Validate(x => !string.IsNullOrEmpty(x.Name), "Name is null")
        .Validate(x => !string.IsNullOrEmpty(x.Surname), "Surname is null")
        .Validate(x => !string.IsNullOrEmpty(x.Fathername), "Fathername is null");

    (bool, List<string>) pair = validator.Get();

    Console.WriteLine(pair.Item1);
}

Материнский объект

Модель Object Mother — это генеративная модель, используемая для облегчения создания объектов с различными конфигурациями. Обычно он используется в контексте тестирования.

ЧИТАТЬ   На проспекте Наставникова из бетономешалки потушили огненную газель

Примером может служить создание аккаунта для физических и юридических лиц. В обоих случаях объекты схожи, но некоторые их свойства различны.

Реализация модели
public class Developer
{
    private string? name;
    private string? description;
    private bool isCompany;

    public void SetName(string name)
    {
        this.name = name;
    }

    public void SetDescription(string description)
    {
        this.description = description;
    }

    public void SetIsCompany(bool flag)
    {
        this.isCompany = flag;
    }
}

public static class DeveloperMother
{
    public static Developer CreatePerson(string name, string description)
    {
        Developer person = new();

        person.SetName(name);

        person.SetDescription(description);

        person.SetIsCompany(false);

        return person;
    }

    public static Developer CreateCompany(string name, string description)
    {
        Developer person = new();

        person.SetName(name);

        person.SetDescription(description);

        person.SetIsCompany(true);

        return person;
    }
}

private static void Main(string[] args)
{
    DeveloperMother.CreatePerson("Developer X", "Mobile apps");
    DeveloperMother.CreateCompany("VALVe", "CS:GO");
}

Пул объектов

Модель пула объектов — это генеративная модель, которая управляет ранее созданными объектами. Он хорошо подходит в тех случаях, когда создание нового объекта требует много ресурсов. Поэтому имеет смысл повторно использовать уже существующие объекты.

Когда клиент запрашивает объект, пул объектов пытается вернуть ранее созданный объект. В противном случае создается новый объект. Такой подход позволяет экономить ресурсы при инициализации и уничтожении объектов.

Реализация модели
public class ObjectPool<T>
{
    private readonly ConcurrentBag<T> _objects;
    private readonly Func<T> _objectGenerator;

    public ObjectPool(Func<T> objectGenerator)
    {
        this._objectGenerator = objectGenerator ?? throw new ArgumentNullException(nameof(objectGenerator));
        this._objects = new ConcurrentBag<T>();
    }

    public T Get()
    {
        return this._objects.TryTake(out T item) ? item : this._objectGenerator();
    }

    public void Return(T item)
    {
        this._objects.Add(item);
    }
}

public class ArrayObject
{
    public int[] Nums { get; set; }

    public ArrayObject()
    {
        this.Nums = new int[1000000];

        Random rand = new();

        for (int i = 0; i < this.Nums.Length; i++)
        {
            this.Nums[i] = rand.Next();
        }
    }

    public static double LOG(int value)
    {
        return Math.Log(value);
    }

    public static double SQRT(int value)
    {
        return Math.Sqrt(value);
    }
}

private static void Main(string[] args)
{
    CancellationTokenSource cancellationTokenSource = new();

    ObjectPool<ArrayObject> objectPool = new(() => new ArrayObject());

    Parallel.For(0, 1000000, (i, state) =>
    {
        ArrayObject example = objectPool.Get();

        Console.WriteLine(ArrayObject.SQRT(i));

        objectPool.Return(example);
        
        if (cancellationTokenSource.Token.IsCancellationRequested)
        {
            state.Stop();
        }
    });
}

Генератор шагов

Модель Step-by-Step Builder — это генеративная модель, используемая для создания сложного объекта в несколько этапов. Это позволяет пользователю полностью создать объект без ошибок.

ЧИТАТЬ   Лучшая часть FAST TV — это отсутствие выбора.
Исходный объект
public class TechniqueDB
{
    public int Id { get; set; }
    public string Date { get; set; }
    public string Image { get; set; }
    public string Title { get; set; }
    public string Subtitle { get; set; }
    public string Theme { get; set; }
    public string Author { get; set; }
    public string Algorithm { get; set; }
    public bool Removed { get; set; }

}
Реализация модели
public class TechniqueBuilder
{
    private readonly TechniqueDB techniqueDB;

    public TechniqueBuilder()
    {
        this.techniqueDB = new TechniqueDB();
    }

    public TechniqueBuilder SetIdentifier(int identifier)
    {
        this.techniqueDB.Id = identifier;
        return this;
    }

    public TechniqueBuilder SetDate(string date)
    {
        this.techniqueDB.Date = date;
        return this;
    }
    public TechniqueBuilder SetTitle(string title)
    {
        this.techniqueDB.Title = title;
        return this;
    }
    public TechniqueBuilder SetSubtitle(string subtitle)
    {
        this.techniqueDB.Subtitle = subtitle;
        return this;
    }

    public TechniqueBuilder SetTheme(string theme)
    {
        this.techniqueDB.Theme = theme;
        return this;
    }

    public TechniqueBuilder SetAuthor(string author)
    {
        this.techniqueDB.Author = author;
        return this;
    }

    public TechniqueBuilder SetAlgorithm(string algorithm)
    {
        this.techniqueDB.Algorithm = algorithm;
        return this;
    }

    public TechniqueBuilder SetImage(string image)
    {
        this.techniqueDB.Image = image;
        return this;
    }

    public TechniqueBuilder IsVisible
    {
        get
        {
            this.techniqueDB.Removed = false;
            return this;
        }
    }
    public TechniqueDB Build()
    {
        return this.techniqueDB;
    }
}
Применить узор
TechniqueBuilder builder = new();

TechniqueDB technique = 
     builder.SetIdentifier(count + 1)
    .SetTitle(this.Name)
    .SetSubtitle(this.Description)
    .SetTheme(this.Theme)
    .SetImage(this.Path)
    .SetAuthor(this.Author)
    .SetAlgorithm(this.Algorithm)
    .SetDate(date)
    .Build();

Продолжение в статье «Сто моделей разработки бизнес-программ. Часть 2.2».

Source

От admin