SOLID на примере JavaScript с chatGPT

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

Запрос:

write me javascript code with solid principles and comment code

Ответ:

// Single Responsibility Principle: Каждая функция должна иметь одну и только одну ответственность function getUserById(userId) {   // Эта функция отвечает за получение пользователя по его ID   return fetch(`https://example.com/users/${userId}`)     .then(response => response.json())     .then(user => {       if (!user) {         throw new Error(`User with ID ${userId} not found`);       }       return user;     }); }  // Open/Closed Principle: Модуль должен быть открыт для расширения, но закрыт для модификации class UserService {   constructor(userRepository) {     // Класс UserService закрыт для модификации, но его можно расширить, передав другую реализацию userRepository.     this.userRepository = userRepository;   }    getUserById(userId) {     return this.userRepository.getUserById(userId);   } }  // Тут по подробней описал снизу, чтобы окончательно понимать суть принципа... // Liskov Substitution Principle: Подтипы должны иметь возможность заменять свои родительские типы без изменения корректности программы. class CachedUserRepository {   constructor(userRepository) {     this.userRepository = userRepository;     this.cache = new Map();   }    getUserById(userId) {     // CachedUserRepository является подтипом UserRepository и может использоваться в качестве замены, не влияя на корректность программы.     if (this.cache.has(userId)) {       return Promise.resolve(this.cache.get(userId));     }     return this.userRepository.getUserById(userId).then(user => {       this.cache.set(userId, user);       return user;     });   } }  // Interface Segregation Principle: Не следует заставлять модуль реализовывать интерфейсы, которые он не использует. class UserController {   constructor(userService) {     this.userService = userService;   }    getUserById(req, res) {     const userId = req.params.id;     this.userService.getUserById(userId)       .then(user => res.json(user))       .catch(err => res.status(404).json({ error: err.message }));   } }  // Dependency Inversion Principle: Модули высокого уровня не должны зависеть от модулей низкого уровня. const userRepository = new UserRepository(); const cachedUserRepository = new CachedUserRepository(userRepository); const userService = new UserService(cachedUserRepository); const userController = new UserController(userService); 

Если вкратце у нас есть userRepository будь то файл или модуль, в котором есть функция getUserByID, что уже является принципом «S».

Далее мы создаем класс UserService, где в качестве конструктора будет этот userRepository, в нем мы инкапсулируем работу выполнение функции getUserByID, в будущем мы можем расширять данный класс для других методов, здесь заложен у нас принцип под буковкой «О».

«L» — заключается в том что мы не меняем родительский класс, а лишь создаем под класс, который не меняет основную логику родительского класса.

Запрос:

tell me about Liskov Substitution Principle more in this example

Ответ:

Принцип замены Лискова (LSP) гласит, что подтипы должны иметь возможность заменять свои родительские типы без изменения правильности программы. В этом примере класс CachedUserRepository является подтипом класса UserRepository, и его можно использовать в качестве замены для UserRepository, не влияя на корректность программы.

Класс CachedUserRepository предназначен для кэширования результатов вызовов метода getUserById, поэтому, если один и тот же идентификатор пользователя запрашивается несколько раз, можно вернуть кэшированное значение вместо выполнения нового вызова API.

У класса CachedUserRepository есть конструктор, который принимает экземпляр UserRepository в качестве аргумента и использует этот экземпляр для фактического вызова API, когда в кеше нет пользователя.

В этом примере класс CachedUserRepository соблюдает принцип подстановки Лискова, поскольку он имеет тот же метод, что и класс UserRepository, он просто добавляет еще одну функцию кэширования и не меняет поведение или возвращаемое значение метода getUserById.

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

«I» — принцип разделение интефейсов гласит, что модуль не следует заставлять реализовывать интерфейсы, которые он не использует.

Класс UserController имеет конструктор, который принимает экземпляр UserService в качестве аргумента. Класс UserController использует только метод getUserById из класса UserService и не использует никаких других методов.

Класс UserService может иметь другие методы, такие как getAllUsers, createUser, updateUser и т. д. Но класс UserController использует только getUserById, ему не нужно реализовывать все методы и ему не нужно знать о существовании других методов.

Следуя ISP, класс UserController не вынужден реализовывать какие-либо ненужные методы, что делает код более гибким и простым для понимания.

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

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

«D» — принцип инверсии зависимости, гласит что классы не могут быть зависемы от класс низкого уровня, из примера в жизни, что мы не можем быть отцами наших отцов.

В заключении… ChatGPT отличная штука для документирования или как минимум поможет вам найти ответы, в которых вы застряли в процессе изучении чего-либо.


ссылка на оригинал статьи https://habr.com/ru/post/712630/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *