Принцип единой ответственности подразумевает то, что:
При нарушении принципа единой ответственности:
class ConcertLineups { constructor(maximumBandLimits) { this.lineups = []; } addBandsToLineup(bandName) { this.lineups.push(bandName); } displayLineups() { console.info(this.lineups); } } const concertLineups = new ConcertLineups(); concertLineups.addBandsToLineup('Warfaze'); concertLineups.addBandsToLineup('Karnival'); concertLineups.addBandsToLineup('SBC'); concertLineups.displayLineups();
Здесь у модуля ConcertLineups есть две причины для изменения:
Сейчас мы просто консолидируем составы. Позже может возникнуть потребность сохранить журнал или отправить его в аналитическую службу.
Более эффективным является подход, использующий принципы единой ответственности:
class Logger { log(message) { console.info(message); } } class ConcertLineups { constructor(maximumBandLimits) { this.lineups = []; this.logger = new Logger(); } addBandsToLineup(bandName) { this.lineups.push(bandName); } displayLineups() { this.logger.log(this.lineups); } } const concertLineups = new ConcertLineups(); concertLineups.addBandsToLineup('Warfaze'); concertLineups.addBandsToLineup('Karnival'); concertLineups.addBandsToLineup('SBC'); concertLineups.displayLineups();
Здесь мы изолируем логирование в отдельном модуле. В любой момент, когда механизм протоколирования будет изменен, мы можем просто обновить класс Logger.
Рассмотрим следующий код, если мы обновляем другой платеж, нам нужно добавить еще один случай переключения. Это модифицирует существующий класс PaymentProcessor.Open closed pr
class StripePayment { constructor(paymentType) { this.paymentType = paymentType; } } class PaypalPayment { constructor(paymentType) { this.paymentType = paymentType; } } class PaymentProcessor { constructor(paymentAdaptar) { this.paymentAdaptar = paymentAdaptar; } pay() { switch(this.paymentAdaptar.paymentType) { case 'Stripe': makeStripePayment(); break; case 'Paypal': makePaypalPayment(); break; } } } const makeStripePayment = () => { // make payment } const makePaypalPayment = () => { // make payment }
Вместо этого мы можем использовать следующий способ, при котором в любой момент, когда нам понадобится новый платежный адаптер, мы можем передать его в PaymentProcessor, без необходимости обновлять класс.
class StripePayment { constructor(paymentType) { this.paymentType = paymentType; } makePayment () { // pay with stripe } } class PaypalPayment { constructor(paymentType) { this.paymentType = paymentType; } makePayment() { // pay with paypal } } class PaymentProcessor { constructor(paymentAdaptar) { this.paymentAdaptar = paymentAdaptar; } pay() { this.paymentAdaptar.makePayment(); } }
Принцип замещения Лискова подразумевает, что:
У нас есть суперкласс, Vehicle. Мы создали два подкласса Car и Cycle из Vehicle. У автомобиля есть метод startEngine. Но, похоже, что у Cycle нет двигателя.
Поэтому объект Vehicle и объект Cycle ведут себя не одинаково. Рассмотрим следующий пример:
class Vehicle { constructor(name) { this.name = name; } startEngine() { console.info(`${this.name} engine started`); } } class Car extends Vehicle { constructor(name) { super(name); } } class Cycle extends Vehicle { constructor(name) { super(name); } startEngine() { throw new Error(`${this.name} does not have an engine.`) } } const car = new Car('My Car'); car.startEngine(); const cycle = new Cycle('My Cycle'); cycle.startEngine();
Чтобы решить эту проблему, мы можем создать еще два подкласса после Vehicle, один MotorVehicle, который имеет двигатель, а другой ManualVehicle, который не имеет двигателя.
class Vehicle { constructor(name) { this.name = name; } } class MotorVehicle { constructor(name) { this.name = name; } startEngine() { console.info(`${this.name} engine started`); } } class ManualVehicle { constructor(name) { this.name = name; } startMoving() { console.info(`${this.name} started moving`); } } class Car extends MotorVehicle { constructor(name) { super(name); } } class Cycle extends ManualVehicle { constructor(name) { super(name); } startEngine() { throw new Error(`${this.name} does not have an engine.`) } } const car = new Car('My Car'); car.startEngine(); const cycle = new Cycle('My Cycle'); cycle.startMoving();
Принцип разделения интерфейсов подразумевает, что интерфейс не должен иметь никаких свойств, которые не используются или не требуются классу.
В следующем примере у нас есть интерфейс Shape, который реализован в классе Square и классе Cube. Мы можем вычислить объем для куба, но не для квадрата. Поэтому, когда мы реализуем Shape для класса Square, он выдает ошибку для метода volume.
interface Shape { area: () => void; volume: () => void; } class Square implements Shape { height: number; width: number; constructor(height: number) { this.height = height; this.width = height; } area () { console.info(this.height * this.width); } volume() { throw new Error('Volume can not valculated on 2d shape'); } } class Cube implements Shape { height: number; width: number; length: number; constructor(height: number, width: number, length: number) { this.height = height; this.width = height; this.length = length; } area () { console.info(this.height * this.width); } volume () { console.info(this.height * this.width * this.length); } } const square = new Square(5); square.area(); square.volume(); const cube = new Cube(5, 6, 7); cube.area(); cube.volume();
L использовать при создании класса Cube.
interface Shape { area: () => void; } interface Shape3D extends Shape { volume: () => void; } class Square implements Shape { height: number; width: number; constructor(height: number) { this.height = height; this.width = height; } area () { console.info(this.height * this.width); } } class Cube implements Shape3D { height: number; width: number; length: number; constructor(height: number, width: number, length: number) { this.height = height; this.width = height; this.length = length; } area () { console.info(this.height * this.width); } volume () { console.info(this.height * this.width * this.length); } } const square = new Square(5); square.area(); const cube = new Cube(5, 6, 7); cube.area(); cube.volume();
Принцип инверсии зависимостей подразумевает,
В следующем коде мы создаем класс CourseService в соответствии с CourseController. Здесь Courservice не должен зависеть от CourseController, вместо этого оба должны зависеть от интерфейса.
class CourseService { get() { console.info('All the courses'); } } class CourseController { constructor(courseService) { this.courseService = courseService; } getAllCourse() { this.courseService.get(); } } const courseService = new CourseService(); const courseController = new CourseController(courseService); courseController.getAllCourse();
Чтобы решить эту проблему, нужен сервис, от которого может зависеть CourseService,
interface Service { get: () => void; } class CourseService implements Service { get() { console.info('All the courses'); } } class CourseController { courseService: Service; constructor(courseService: Service) { this.courseService = courseService; } getAllCourse() { this.courseService.get(); } } const courseService = new CourseService(); const courseController = new CourseController(courseService); courseController.getAllCourse();
31.03.2023 11:40
Laravel - это мощный PHP-фреймворк, используемый для создания масштабируемых и надежных веб-приложений. Одним из преимуществ Laravel является его обширная экосистема пакетов и стартовых наборов, которые делают создание веб-приложений более быстрым и эффективным. В этой статье мы рассмотрим лучшие...
31.03.2023 11:16
Как безопасно обрабатывать неопределенные и нулевые значения в коде с помощью Nullish Coalescing
31.03.2023 11:06
Создание API-ресурса Laravel может быть непростой задачей. Она требует глубокого понимания возможностей Laravel и лучших практик, чтобы обеспечить масштабируемость, производительность и безопасность вашего API. В этой статье мы рассмотрим несколько советов по созданию ресурсов API Laravel,...
31.03.2023 10:15
Справочный центр - это веб-сайт, где клиенты могут найти ответы на свои вопросы и решения своих проблем. Созданный для решения многих распространенных вопросов, которые получает бренд, справочный центр должен упрощать клиентам поиск ответов, которые они ищут.
30.03.2023 14:11
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных способов решения этой задачи является использование запросов AJAX. Однако существуют определенные ситуации, когда AJAX не подходит, например, когда...
30.03.2023 13:54
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.