Паттерн проектирования — это продуманный способ построения исходного кода программы для решения часто возникающих в повседневном программировании проблем проектирования. Иными словами, это уже придуманное решения, для типичной задачи. При этом паттерн не готовое решение, а просто алгоритм действий, который должен привести к желаемому результату. Давайте рассмотрим один из наиболее часто используемых поведенческих паттернов — Шаблонный метод (Template method).

Как я уже писал ранее, существует три вида паттернов проектирования:

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

Шаблонный метод (Template method) — это поведенческий паттерн, который позволяет определить каркас алгоритма, обособившись от конкретной реализации всех или некоторых шагов, позволяя делать это подклассам, при этом не нарушая структурной целостности алгоритма. То есть, Шаблонный метод задет основу алгоритма и позволяет наследникам вносить поправки, не меняя алгоритм в целом.

Давайте рассмотрим диаграмму паттерна Шаблонный метод

Шаблонный метод

  • AbstractClass — определяет невиртуальный метод TemplateMethod, который вызывает внутри примитивные операции PrimitiveOperation1(), PrimitiveOperation2()
  • ConcreteClass — реализует примитивные шаги алгоритма.

Рассмотрим основную логику работы паттерна Шаблонный метод. В базовом классе определен метод, например пусть это будет приготовления пирога. Он определяет последовательность действий замешать тесто, добавить начинку, приготовить в духовке. Данная последовательность будет идентичной для всех пирогов, а вот конкретные реализации для яблочного и мясного пирога будут кардинально отличаться на всех этапах приготовления. Таким образом шаблонный метод задает последовательность определенных действий, а наследники реализуют эти действия в соответствии со своими требованиями и особенностями.

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

  1. Приготовить тесто
  2. Приготовить начинку
  3. Запечь в духовке

Последовательность этих действий будет одинакова для любого пирога. А также определим сами методы-этапы приготовления не реализуя их.

namespace TemplateMethod
{
    /// <summary>
    /// Базовый класс пирога.
    /// </summary>
    public abstract class PieBase
    {
        /// <summary>
        /// Приготовить пирог.
        /// </summary>
        public void Cook()
        {
            CreateDough();
            CreateFilling();
            Fry();
        }

        /// <summary>
        /// Замешать тесто.
        /// </summary>
        protected abstract void CreateDough();

        /// <summary>
        /// Приготовить начинку.
        /// </summary>
        protected abstract void CreateFilling();

        /// <summary>
        /// Запечь пирог в духовке.
        /// </summary>
        protected abstract void Fry();
    }
}

Теперь создадим два класса наследника, которые уже будут конкретно реализовывать этапы приготовления.

using System;

namespace TemplateMethod
{
    public class ApplePie : PieBase
    {
        /// <inheritdoc />
        protected override void CreateDough()
        {
            Console.WriteLine("Используем слоеное тесто.");
        }

        /// <inheritdoc />
        protected override void CreateFilling()
        {
            Console.WriteLine("Используем яблочную начинку.");
        }

        /// <inheritdoc />
        protected override void Fry()
        {
            Console.WriteLine("Запекаем в духовке при температуре 180 градусов в течении 30 минут.");
        }

        /// <summary>
        /// Приведение объекта к строке.
        /// </summary>
        /// <returns> Тип пирога. </returns>
        public override string ToString()
        {
            return "Яблочный пирог";
        }
    }
}
using System;

namespace TemplateMethod
{
    public class MeatPie : PieBase
    {
        /// <inheritdoc />
        protected override void CreateDough()
        {
            Console.WriteLine("Используем дрожжевое тесто.");
        }

        /// <inheritdoc />
        protected override void CreateFilling()
        {
            Console.WriteLine("Используем мясную начинку.");
        }

        /// <inheritdoc />
        protected override void Fry()
        {
            Console.WriteLine("Запекаем в духовке при температуре 210 градусов в течении 50 минут.");
        }

        /// <summary>
        /// Приведение объекта к строке.
        /// </summary>
        /// <returns> Тип пирога. </returns>
        public override string ToString()
        {
            return "Мясной пирог";
        }
    }
}

Ну и наконец создадим экземпляры этих классов и проверим их работу. Обратите внимание, что при обращении к конкретным экземплярам класса не обращаемся к этапам приготовления, мы просто вызываем наш шаблонный метод.

using System;
using System.Text;

namespace TemplateMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            // Создаем два вида пирога.
            var meatPie = new MeatPie();
            var applePie = new ApplePie();

            // Готовим мясной пирог.
            Console.WriteLine(meatPie);
            meatPie.Cook();
            Console.ReadLine();

            // Готовим яблочный пирог.
            Console.WriteLine(applePie);
            applePie.Cook();
            Console.ReadLine();
        }
    }
}

В результате получаем следующий результат

Исходный код приложения можно скачать из репозитория github https://github.com/shwanoff/TemplateMethod

 
×
%d такие блоггеры, как: