Понимание шаблона Builder в C#

Определение шаблона построителя. Шаблон построителя отделяет спецификацию сложного объекта от его фактической конструкции. Один и тот же процесс построения может создавать разные представления.

ну, у меня есть пример кода шаблона Builder, подобный этому

class Director
    {
        // Build a Product from several parts
        public void Construct(IBuilder builder)
        {
            builder.BuildPartA();
            builder.BuildPartB();
            builder.BuildPartB();
        }
    }

    interface IBuilder
    {
        void BuildPartA();
        void BuildPartB();
        Product GetResult();
    }

    class Builder1 : IBuilder
    {
        private Product product = new Product();
        public void BuildPartA()
        {
            product.Add("PartA ");
        }

        public void BuildPartB()
        {
            product.Add("PartB ");
        }

        public Product GetResult()
        {
            return product;
        }
    }

    class Builder2 : IBuilder
    {
        private Product product = new Product();
        public void BuildPartA()
        {
            product.Add("PartX ");
        }

        public void BuildPartB()
        {
            product.Add("PartY ");
        }

        public Product GetResult()
        {
            return product;
        }
    }

    class Product
    {
        List<string> parts = new List<string>();
        public void Add(string part)
        {
            parts.Add(part);
        }

        public void Display()
        {
            Console.WriteLine("\nProduct Parts -------");
            foreach (string part in parts)
                Console.Write(part);
            Console.WriteLine();
        }
    }

    public class Client
    {

        public static void Main()
        {
            // Create one director and two builders
            Director director = new Director();

            IBuilder b1 = new Builder1();
            IBuilder b2 = new Builder2();

            // Construct two products
            director.Construct(b1);
            Product p1 = b1.GetResult();
            p1.Display();

            director.Construct(b2);
            Product p2 = b2.GetResult();
            p2.Display();

            Console.Read();
        }
    }

Теперь я внес некоторые изменения в приведенный выше код. Представляет ли приведенный ниже код шаблон Builder?

class Director
    {
        public void Construct(IBuilder builder)
        {
            builder.BuildPartA();
            builder.BuildPartB();
            builder.GetResult();
        }
    }

    interface IBuilder
    {
        void BuildPartA();
        void BuildPartB();
        void GetResult();
    }

    class Builder1 : IBuilder
    {
        List<string> product = new List<string>();
        public void BuildPartA()
        {
            product.Add("PartA ");
        }

        public void BuildPartB()
        {
            product.Add("PartB ");
        }

        public void GetResult()
        {
            foreach (var p in product)
            {
                Console.WriteLine("the product created is :" + p);
            }
        }
    }

    class Builder2 : IBuilder
    {
        List<string> product = new List<string>();
        public void BuildPartA()
        {
            product.Add("PartX ");
        }

        public void BuildPartB()
        {
            product.Add("PartY ");
        }

        public void GetResult()
        {
            foreach (var p in product)
            {
                Console.WriteLine("the product created is :" + p);
            }
        }
    }
    public class Client
    {

        public static void Main()
        {

            Director director = new Director();
            IBuilder b1 = new Builder1();
            IBuilder b2 = new Builder2();
            director.Construct(b1);
            director.Construct(b2);

            Console.Read();
        }
    }

Примечание:

Я удалил класс продукта из второго примера кода.

Мой вопрос: создание класса, который обрабатывает все объекты и вызывает метод упорядоченным образом, делает его шаблоном Builder? Просто хотел убедиться, что я понял концепцию Builder Pattern. заранее спасибо

ОБНОВЛЕНИЕ 1

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

 interface IRoutine {
        void WakeUp();
        void GoToSchool();
        void ListenToMusic();
        void Sleep();
    }
    class person1 : IRoutine
    {
        public void GoToSchool()
        {
            Console.WriteLine("going to school");
        }

        public void ListenToMusic()
        {
            Console.WriteLine("litening to music");
        }

        public void Sleep()
        {
            Console.WriteLine("tring to sleep");
        }

        public void WakeUp()
        {
            Console.WriteLine("good morning !!!");
        }
    }
    class person2 : IRoutine
    {
        public void GoToSchool()
        {
            Console.WriteLine("going to school");
        }

        public void ListenToMusic()
        {
            Console.WriteLine("litening to music");
        }

        public void Sleep()
        {
            Console.WriteLine("tring to sleep");
        }

        public void WakeUp()
        {
            Console.WriteLine("good morning !!!");
        }
    }
    class Builder {
        public void Construct(IRoutine routine) {
            routine.WakeUp();
            routine.GoToSchool();
            routine.ListenToMusic();
            routine.Sleep();
        }
    }
    class Client {
        static void Main() {
            Builder builder = new Builder();
            IRoutine r1 = new person1();
            IRoutine r2 = new person2();

            builder.Construct(r1);
            builder.Construct(r2);

            Console.Read();
        }
    }

Является ли недавний пример, который я предоставил шаблоном Builder? Если нет, то почему это не шаблон Builder, пожалуйста, помогите мне понять.


person Lijin Durairaj    schedule 29.10.2016    source источник
comment
соответствует критериям Builder Pattern Я думаю, что вы неправильно думаете о шаблонах. Нет такого критерия, шаблон является скорее ориентиром, чем то, что вы можете запустить статический анализатор кода, который скажет вам, является ли это шаблоном Builder или нет.   -  person Filip Cordas    schedule 29.10.2016
comment
@FilipCordas извините, я хотел вас спросить, является ли второй пример, который я вам предоставил, шаблоном Builder? Я просто хотел убедиться для себя, что я изучил шаблон Строителя, вот и все... спасибо за вашу помощь   -  person Lijin Durairaj    schedule 29.10.2016


Ответы (3)


Ваш последний фрагмент не является примером шаблона строителя. Шаг, на котором вы создаете конечный объект, является ключевой частью шаблона, и, удаляя этот шаг, ваш класс строителя фактически становится фактическим, сконструированным (изменяемым) объектом. Другими словами, если бы string был изменчивым, не существовало бы StringBuilder, вы бы просто использовали гипотетический метод string.Append для изменения конечного объекта. Или, если бы StringBuilder возвращало что-либо, кроме сконструированного string, это не было бы названо StringBuilder.

Чтобы оправдать существование строителя на практике, я бы ожидал, что он либо:

  1. Предоставьте интерфейс для создания неизменяемого объекта, а затем "заморозьте" его, т. е. верните неизменяемый построенный экземпляр (хороший пример – StringBuilder).

  2. Обеспечьте немного более чистый (например, плавный) интерфейс для создания экземпляра объекта по сравнению, скажем, с огромным количеством параметров конструктора. Однако, если конечный объект является изменяемым, это затрудняет обоснование этого, поскольку вы все равно можете установить отдельные свойства.

В некоторых примерах построитель используется для обеспечения дополнительного уровня абстракции для построения объекта (т. е. позволяет создавать разные конкретные типы одинаковым образом), а затем передает абстрактный построитель «директору», который использует его для построения объекта. но я считаю, что этот шаг не имеет отношения к шаблону. Я бы даже пошел дальше и сказал, что абстрактные конструкторы с несколькими методами кажутся антипаттернами, потому что они привязывают построение каждого конкретного объекта к одному и тому же процессу строительства. Чтобы лучше понять мою точку зрения, подумайте, как бы вы реализовали BoatBuilder в приведенном здесь примере. .

person Groo    schedule 31.10.2016
comment
я не мог понять пример, который вы привели, я обновил новый пример, не могли бы вы пройти через него, чтобы помочь мне понять шаблон Builder.... спасибо :) - person Lijin Durairaj; 31.10.2016
comment
В первом фрагменте у вас есть метод GetResult, который возвращает экземпляр Product. Вот почему он называется шаблоном строителя, потому что он строит Product, поэтому Builder1 и Builder2 являются строителями. Во втором фрагменте вы изменили метод на метод void, что означает, что этот метод ничего не возвращает, и, в свою очередь, это означает, что класс ничего не создает, а вместо этого мутирует сам себя. Третий пример еще дальше, потому что в интерфейсе IRoutine нет даже метода GetResult, а вы переименовали Director в Builder. - person Groo; 31.10.2016
comment
Другими словами, вам не нужен директор, это необязательно для этого шаблона. Забудьте о реализации и сосредоточьтесь на том, что должен делать конструктор. StringBuilder — прекрасный пример строителя. 1) вы создаете новый StringBuilder, 2) вы используете методы Append для изменения построителя и 3) вы вызываете метод StringBuilder.ToString() для завершения построения и возврата неизменяемого результата. Куча методов, записывающих в Console, ничего не строит, самые важные строки в начальном сниппете — product.Add(*) и return product. - person Groo; 31.10.2016

ИМХО, это реализация шаблона строителя. Единственная принципиальная разница между вашей реализацией и приведенным вами примером - это тип "продукта". В вашей реализации вы создаете конкатенированную строку (я уверен, вы знаете, что есть более простые способы сделать это!), но образец создает объект типа «Продукт».

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

Шаблон построителя можно использовать для отделения построения сложного объекта от его представления. Я бы не стал классифицировать строку как сложный объект, который заслуживает реализации такого сложного кода, но вы все еще используете конструктор.

Я согласен с комментарием, оставленным Филипом Кордасом, если вы знаете, как создать свой образец кода, у вас есть возможность адаптировать его в соответствии со своими потребностями. В этом сила знания шаблонов проектирования. Согласен ли другой разработчик с тем, что ваша адаптация является «чистой» реализацией шаблона построителя, не имеет значения; надеюсь, у вас есть хорошо спроектированный код, отвечающий вашим потребностям.

person mark_h    schedule 31.10.2016

На мой взгляд, это не строительный шаблон, но его можно просто изменить. Прямо сейчас единственное, что вы строите, это сам строитель. Я думаю, что это сделало бы его «правильным» шаблоном построителя, изменив ваш метод GetResult на:

public List<string> GetResult()
        {
           return product;
        }

Таким образом, вы создаете список строк внутри вашего IBuilder (это общее правило, обычно, когда вы копируете и вставляете, это означает, что вы можете переосмыслить свою реализацию). Имена могут дать вам понять, что ваш метод get не получает ничего, кроме фактической печати. Но мне кажется, что ваша реализация намного хуже, поскольку нарушает принцип единой ответственности. Прямо сейчас вы можете изменить класс, если хотите изменить процесс сборки или хотите новый способ его отображения, тогда как первая реализация имеет только один.

person Filip Cordas    schedule 31.10.2016