diff --git a/docs/book/ru/Chapter_2__Software_Design_Principles_and_Patterns.md b/docs/book/ru/Chapter_2__Software_Design_Principles_and_Patterns.md index 39de8079b..bd2d43993 100644 --- a/docs/book/ru/Chapter_2__Software_Design_Principles_and_Patterns.md +++ b/docs/book/ru/Chapter_2__Software_Design_Principles_and_Patterns.md @@ -79,7 +79,7 @@ head: Принцип *композиции над наследованием* заимствован непосредственно из **объектно-ориентированного программирования** (**ООП**). Он гласит, что объект должен пытаться использовать функциональность других объектов, когда это необходимо, путем ссылки на них или инстанцирования, а не создавать большое и сложное дерево классов наследования для добавления такой функциональности. -В наши дни, JavaScript по своей сути является *функциональным* языком, хотя и поддерживает множество парадигм, включая черты ООП, поэтому этот принцип также применим. Есть одно предостережение для тех, кто переходит с ООП на JavaScript, - не +В наши дни, JavaScript по своей сути является *функциональным* языком, хотя и поддерживает множество парадигм, включая черты ООП, поэтому этот принцип также применим. Есть одно предостережение для тех, кто переходит с ООП на JavaScript - не поддавайтесь искушению рассматривать JavaScript как чистый ООП-язык. Это может привести к ненужным сложностям, вместо того чтобы воспользоваться достоинствами языка. В Vue 3 не существует расширения или наследования компонентов. Когда нам нужна общая или наследуемая функциональность, у нас есть хороший набор инструментов для замены парадигмы наследования. Как соблюсти этот принцип, используя *композитные компоненты*, мы увидим позже в главе 4, *Композиция пользовательского интерфейса с помощью компонентов.* @@ -124,14 +124,14 @@ head: Этот принцип относится главным образом к тому, как *вы пишете* код. Здесь я должен подчеркнуть, что KIC непосредственно относится к двум категориям, которые сильно влияют на веб-приложения и приложения Vue 3: - Как вы форматируете свой код -- Как вы упорядотичиваете события и переменные +- Как вы упорядочиваете события и переменные Первый пункт включает в себя использование кодовых соглашений, комментариев и отступов для организации кода и логической группировки функций. Например, если у вас есть методы, которые работают с операциями **создания, чтения, обновления и удаления** (**CRUD**), то лучше всего разместить их в коде рядом друг с другом, а не разбрасывать по всему исходному файлу. Многие **интегрированные среды разработки** (**IDE**) содержат функции, позволяющие сворачивать или разворачивать внутренний код функций. Это помогает быстро просматривать и находить в коде участки с похожей логикой. -Вторая часть этого принципа связана с обработкой памяти и ссылок. JavaScript имеет очень хороший сборщик мусора, функция которого заключается в отбрасывании неиспользуемых данных для освобождения памяти. Однако бывают случаи, когда алгоритм не может освободить ресурсы из-за того, что ссылка все еще не выполнена. Если вы работали с другими языками, такими как C/C++, то эта проблема может показаться вам знакомой, поскольку вам необходимо вручную резервировать и освобождать память, когда она не используется. +Вторая часть этого принципа связана с обработкой памяти и ссылок. JavaScript имеет очень хороший сборщик мусора, функция которого заключается в отбрасывании неиспользуемых данных для освобождения памяти. Однако бывают случаи, когда алгоритм не может освободить ресурсы из-за наличия оставшихся ссылок. Если вы работали с другими языками, такими как C/C++, то эта проблема может показаться вам знакомой, поскольку вам необходимо вручную резервировать и освобождать память, когда она не используется. В JavaScript, если вы регистрируете функцию для прослушивания события, лучше всего вручную снять ее с регистрации в соответствующем событии жизненного цикла компонента, когда она больше не нужна. Это позволит избежать утечек и нерационального использования памяти, а также предотвратить некоторые риски безопасности (которые выходят за рамки данной книги). @@ -204,7 +204,7 @@ head: На практике применение шаблона дает большой простор для творчества. Этой теме посвящены целые книги, в которых приводится больше подробностей, чем позволяет объем данной книги. На следующих страницах мы рассмотрим наиболее часто встречающиеся, на мой взгляд, шаблоны, которые следует иметь в виду при работе с приложениями Vue 3. -Несмотря на то, что для целей изучения мы видим их по отдельности, в реальности часто реализация накладывает, смешивает и заключает в себе несколько шаблонов в одном фрагменте кода. Например, вы можете использовать **синглтон** для выполнения функций **декоратора** и **прокси** для упрощения или изменения взаимодействия между сервисами в вашем приложении (на самом деле мы будем делать это довольно часто, и полный код можно увидеть в Глава 8, *Многопоточность с Web Workers*. +Несмотря на то, что для целей изучения мы видим их по отдельности, в реальности часто реализация накладывает, смешивает и заключает в себе несколько шаблонов в одном фрагменте кода. Например, вы можете использовать **синглтон** для выполнения функций **декоратора** и **прокси** для упрощения или изменения взаимодействия между сервисами в вашем приложении (на самом деле мы будем делать это довольно часто, и полный код можно увидеть в Глава 8, *Многопоточность с Web Workers*). Шаблоны проектирования также можно понимать как *лучшие практики* в области программной инженерии и разработки. А противоположную ей, *плохую практику*, часто называют **антипаттерном**. Антипаттерны - это "решения", которые, даже устраняя проблему в краткосрочной перспективе, создают проблемы и плохие последствия в дальнейшем. Они порождают необходимость обхода проблемы и дестабилизируют всю структуру и реализацию. @@ -258,9 +258,8 @@ head: Вот краткое эмпирическое правило, позволяющее понять, когда следует применять этот шаблон: - Когда необходимо убедиться, что доступ к ресурсу осуществляется только через один шлюз, например, к глобальному состоянию приложения -- Когда необходимо инкапсулировать или упростить поведение или взаимодействие (используется в сочетании с другими шаблонами). Например, объект доступа к API. -- Когда *затраты* на многочисленные инстанцирования являются большими.Например, создание web workers. -- +- Когда необходимо инкапсулировать или упростить поведение, или взаимодействие (используется в сочетании с другими шаблонами). Например, объект доступа к API. +- Когда *затраты* на многочисленные инстанцирования являются большими. Например, создание web workers. #### Реализация @@ -418,7 +417,7 @@ projects.setDBManager(dbManager); Этот подход лучше, чем прямое присвоение внутреннего атрибута, но все равно нужно не забыть выполнить присвоение перед использованием любых методов объекта. -::: Совет из Лучших практик +::: tip Совет из Лучших практик Какой бы подход вы ни использовали для инъекции зависимостей, он должен оставаться неизменным во всей вашей кодовой базе. ::: @@ -439,7 +438,7 @@ const dependencyService = {                         //1 dependencies: {},                          //2     provide(name, dependency){                      //3         this.dependencies[name] = dependency        //4 -        return this;              ;                 //5 +        return this;                                //5 }     inject(name){                                   //6 return this.dependencies[name] ?? null;     //7 @@ -456,7 +455,7 @@ export default dependencyService; 4. Здесь мы просто используем имя в качестве имени поля и присваиваем зависимость, переданную в качестве аргумента (заметьте, мы не проверяем уже существующие имена и т.д.). 5. Здесь мы возвращаем исходный объект, в основном для удобства, чтобы можно было выстроить цепочку вызовов. 6. Функция **inject** принимает имя, зарегистрированное в **provide** функции. -7. Мы возвращаем зависимость или **null** , если она не найдена. +7. Мы возвращаем зависимость или **null**, если она не найдена. Получив синглтон, мы можем использовать его во всем приложении для распределения зависимостей по мере необходимости. Для этого нам нужен родительский объект, чтобы импортировать их и заполнить сервис. Вот пример того, как это может выглядеть: @@ -537,7 +536,7 @@ on(event_name, fn = () => {}) {                             if(!this.events[event_name]) {         this.events[event_name] = []     } -    this.events[event_name].push(fn)                       //3 +    this.events[event_name].push(fn)                        //3 } emit(event_name, data){                                     //4     if(!this.events[event_name]){ @@ -654,7 +653,7 @@ class CommandInvoker{ - Вам необходимо сохранить оригинальный немодифицированный API, но в то же время: - Необходимо обрабатывать входные или выходные данные для клиента - - Необходимо перехватывать каждый вызов API для добавления внутренней функциональности, например, операций обслуживания, повышения производительности, Проверка ошибок, и валидация + - Необходимо перехватывать каждый вызов API для добавления внутренней функциональности, например, операций обслуживания, повышения производительности, проверка ошибок и валидация - Цель является дорогим ресурсом, поэтому прокси может реализовать логику для использования его операций (например, кэш) - Вам необходимо изменить клиента или цель, но вы не можете изменить API - Вам необходимо поддерживать обратную совместимость @@ -673,7 +672,7 @@ class CommandInvoker{ let temperature = { celsius:0, fahrenheit: 32 },                    //1     handler = {                                               //2 set(target, key, value){                                    //3 - target[key] = value;                                 //4 + target[key] = value;                                    //4 switch(key) { case "celsius":         target.fahrenheit = calculateFahrenheit(value); //5