В нашем предыдущем блоге мы обсуждали необходимость свободного наследования компоновщика, а также преимущества периодического расширения существующего компоновщика при соблюдении принципов SOLID (т. е. с использованием принципа Open-Closed). Здесь мы поговорим об очень уникальной ситуации со сборщиками, которые могут пригодиться, когда требуется поэтапное создание объекта.

Давайте рассмотрим пример: в нашем предыдущем блоге мы создали класс Сотрудник, но теперь требования изменились, и мы должны установить зарплату на основе назначения, поэтому взгляните на наш новый класс Сотрудник.

public enum Designations
{
    Employee,
    Manager,
    TechnicalLead
}

public class Employee
{
    public Guid Id { get; set; }
    public Designations Designation { get; set; }
    public decimal Salary { get; set; }
}

public class EmployeeBuilder
{
    private Employee _employee = new Employee();

    public EmployeeBuilder Create(Designations desg, decimal salary)
    {
        _employee = new Employee
        {
            Id = Guid.NewGuid(),
            Designation = desg,
            Salary = salary
        };

        return this;
    }

    public Employee Build()
    {
        return _employee;
    }
}

Приведенный выше пример удовлетворит наши основные потребности в создании объектов, но в коде есть очень существенный недостаток. В настоящее время мы предоставляем пользователю метод Create(), и хотя мы принимаем как назначение сотрудника, так и его оклад, что произойдет, если пользователь введет неверные назначение и оклад? Поскольку пользователь должен беспокоиться о бизнес-логике, это решение не кажется идеальным. Другое дело, что мы не должны позволять пользователям устанавливать зарплату; вместо этого оно должно быть установлено как свойство в соответствии с нашей бизнес-логикой. Вы можете задаться вопросом, что нужно сделать, чтобы исправить это, и ответ очень прост: мы можем использовать Stepwise Builder, чтобы закрыть любую лазейку, которая в настоящее время присутствует.

namespace Builder.StepwiseBuilder
{
    public enum Designations
    {
        Employee,
        Manager,
        TechnicalLead
    }

    public interface IDesignationBuilder
    {
        ISalaryBuilder WithDesignation(Designations designation);
    }

    public interface ISalaryBuilder
    {
        IEmployeeBuilder AssignSalary();
    }

    public interface IEmployeeBuilder
    {
        Employee Build();
    }

    public class Employee
    {
        public Guid Id { get; set; }
        public Designations Designation { get; set; }
        public decimal Salary { get; set; }

        public static Builder CreateBuilder()
        {
            return new Builder();
        }

        public class Builder : IDesignationBuilder, ISalaryBuilder, IEmployeeBuilder
        {
            private Employee _employee = new Employee();

            public ISalaryBuilder WithDesignation(Designations designation)
            {
                _employee.Designation = designation;
                return this;
            }

            public IEmployeeBuilder AssignSalary()
            {
                switch (_employee.Designation)
                {
                    case Designations.Employee:
                        _employee.Salary = 1000;
                        break;
                    case Designations.Manager:
                        _employee.Salary = 5000;
                        break;
                    case Designations.TechnicalLead:
                        _employee.Salary = 10000;
                        break;
                    default:
                        throw new InvalidOperationException("Designation not supported, please pass valid designation");
                }

                return this;
            }

            public Employee Build()
            {
                return _employee;
            }
        }
    }

    public class StepWiseBuilderExample
    {
        public static void Main(string[] args)
        {
            var employee = Employee.CreateBuilder()
                                   .WithDesignation(Designations.Employee)
                                   .AssignSalary()
                                   .Build();

            Console.WriteLine($"{employee.Designation} gets paid ${employee.Salary}");
        }
    }
}

Здесь мы используем разные интерфейсы для разных целей, а затем создаем цепочку, чтобы выполнять операции на определенных этапах. Как видите, IDesignationBuilder возвращает ISalaryBuilder и т. д., так что мы можем выполнять операции, связанные с окладом, только после установки назначения. Таким образом, мы непреднамеренно заставляем пользователей выполнять шаги, а также следим за соблюдением бизнес-логики.

Наконец, я просто хотел подчеркнуть, насколько важен этот тип Builder и как его можно использовать во многих различных контекстах, особенно при выполнении предметно-ориентированного программирования, когда вам нужно убедиться, что объекты создаются с определенной целью и что пользователи следуют инструкциям. надлежащие процедуры для создания объектов.

Так что это все для этого сообщения в блоге. В нашем следующем блоге мы рассмотрим другие способы реализации сборщиков и поговорим о некоторых их приложениях. До тех пор.

Удачного кодирования…!!!