웹 프론트엔드 JS 튜토리얼 JavaScript의 견고한 원칙

JavaScript의 견고한 원칙

Dec 28, 2024 pm 07:34 PM

OOP 패러다임의 도입으로 상속, 다형성, 추상화, 캡슐화와 같은 주요 프로그래밍 개념이 대중화되었습니다. OOP는 Java, C, C#, JavaScript 등과 같은 여러 언어로 구현되어 널리 수용되는 프로그래밍 패러다임이 되었습니다. OOP 시스템은 시간이 지남에 따라 더욱 복잡해졌지만 소프트웨어는 여전히 변화에 저항했습니다. 소프트웨어 확장성을 향상시키고 코드 강성을 줄이기 위해 Robert C. Martin(일명 Bob 삼촌)은 2000년대 초반에 SOLID 원칙을 도입했습니다.

SOLID는 소프트웨어 엔지니어가 유지 관리 가능하고 확장 가능하며 유연하게 설계하고 작성하는 데 도움이 되는 단일 책임 원칙, 개방형 폐쇄 원칙, Liskov 대체 원칙, 인터페이스 분리 원칙, 종속성 반전 원칙 등 일련의 원칙으로 구성된 약어입니다. 암호. 그 목표는 무엇입니까? 객체 지향 프로그래밍(OOP) 패러다임에 따라 개발된 소프트웨어의 품질을 향상시킵니다.

이 기사에서는 SOLID의 모든 원칙을 자세히 살펴보고 가장 인기 있는 웹 프로그래밍 언어 중 하나인 JavaScript를 사용하여 구현되는 방법을 설명합니다.

단일 책임 원칙(SRP)

SOLID의 첫 글자는 단일 책임 원칙을 나타냅니다. 이 원칙은 클래스나 모듈이 하나의 역할만 수행해야 함을 시사합니다.

간단히 말하면, 클래스에는 단일한 책임이나 변경 이유가 있어야 합니다. 클래스가 둘 이상의 기능을 처리하는 경우 다른 기능에 영향을 주지 않고 한 기능을 업데이트하는 것은 까다롭습니다. 후속 문제로 인해 소프트웨어 성능이 저하될 수 있습니다. 이러한 종류의 문제를 피하려면 우려 사항이 분리된 모듈식 소프트웨어를 작성하는 데 최선을 다해야 합니다.

클래스에 책임이나 기능이 너무 많으면 수정하기가 어렵습니다. 단일 책임 원칙을 사용하면 모듈식이고 유지 관리가 더 쉽고 오류가 발생할 가능성이 적은 코드를 작성할 수 있습니다. 사람 모델을 예로 들어보겠습니다.

class Person {
    constructor(name, age, height, country){
      this.name = name
      this.age = age
      this.height = height
      this.country = country
  }
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

위 코드는 괜찮은 것 같죠? 좀 빠지는. 샘플 코드는 단일 책임 원칙을 위반합니다. Person 클래스는 Person의 다른 인스턴스를 생성할 수 있는 유일한 모델이 아닌,calculateAge, GreetingPerson 및 getPersonCountry와 같은 다른 책임도 가집니다.

Person 클래스에서 처리하는 이러한 추가 책임으로 인해 코드의 한 측면만 변경하기가 어렵습니다. 예를 들어,calculateAge를 리팩터링하려고 시도한 경우 Person 모델도 리팩터링해야 할 수도 있습니다. 코드 베이스가 얼마나 작고 복잡한지에 따라 오류 없이 코드를 재구성하는 것이 어려울 수 있습니다.

잘못된 부분을 수정해 보겠습니다. 다음과 같이 책임을 여러 클래스로 나눌 수 있습니다.

class Person {
    constructor(name, age, height, country){
      this.name = name
      this.age = age
      this.height = height
      this.country = country
  }
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

위의 샘플 코드에서 볼 수 있듯이 책임을 분리했습니다. Person 클래스는 이제 새로운 사람 객체를 생성할 수 있는 모델입니다. 그리고 PersonUtils 클래스에는 사람의 나이를 계산하는 단 하나의 책임이 있습니다. PersonService 클래스는 인사말을 처리하고 각 사람의 국가를 보여줍니다.

원한다면 이 프로세스를 더 줄일 수도 있습니다. SRP에 따라 우리는 클래스의 책임을 최소한으로 분리하여 문제가 있을 때 큰 번거로움 없이 리팩토링과 디버깅을 수행할 수 있기를 원합니다.

기능을 별도의 클래스로 나누어 단일 책임 원칙을 고수하고 각 클래스가 애플리케이션의 특정 측면을 담당하도록 보장합니다.

다음 원칙으로 넘어가기 전에 SRP를 준수한다고 해서 각 클래스가 엄격하게 단일 메소드나 기능을 포함해야 한다는 의미는 아닙니다.

그러나 단일 책임 원칙을 고수한다는 것은 클래스에 기능을 의도적으로 할당해야 함을 의미합니다. 수업이 수행하는 모든 것은 모든 면에서 밀접하게 연관되어 있어야 합니다. 여러 클래스가 여기저기 흩어져 있지 않도록 주의해야 하며, 코드 베이스에서 클래스가 너무 커지는 것을 반드시 피해야 합니다.

개방-폐쇄 원칙(OCP)

개방-폐쇄 원칙은 소프트웨어 구성 요소(클래스, 함수, 모듈 등)가 확장에는 개방되고 수정에는 폐쇄되어야 함을 명시합니다. 나는 당신이 무슨 생각을 하는지 알고 있습니다. 예, 이 아이디어는 처음에는 모순적으로 보일 수도 있습니다. 그러나 OCP는 소스 코드를 반드시 수정하지 않고도 확장이 가능하도록 소프트웨어를 설계하라고 요구하고 있습니다.

OCP는 대규모 코드 기반을 유지하는 데 매우 중요합니다. 이 지침을 통해 코드가 손상될 위험이 거의 또는 전혀 없이 새로운 기능을 도입할 수 있기 때문입니다. 새로운 요구 사항이 발생할 때 기존 클래스나 모듈을 수정하는 대신 새 구성 요소를 추가하여 관련 클래스를 확장해야 합니다. 이 작업을 수행하면서 새 구성 요소로 인해 시스템에 버그가 발생하지 않는지 확인하세요.

ES6 클래스 상속 기능을 사용하면 JavaScript에서 OC 원칙을 구현할 수 있습니다.

다음 코드 조각은 앞서 언급한 ES6 클래스 키워드를 사용하여 JavaScript에서 개방형-폐쇄형 원칙을 구현하는 방법을 보여줍니다.

class Person {
    constructor(name, dateOfBirth, height, country){
      this.name = name
      this.dateOfBirth = dateOfBirth
      this.height = height
      this.country = country
  }
}

class PersonUtils {
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}

const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); 
console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth));

class PersonService {
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

위 코드는 잘 작동하지만 직사각형의 면적만 계산하는 것으로 제한됩니다. 이제 계산해야 할 새로운 요구 사항이 있다고 상상해 보십시오. 예를 들어 원의 면적을 계산해야 한다고 가정해 보겠습니다. 이를 충족하려면 ShapeProcessor 클래스를 수정해야 합니다. 그러나 JavaScript ES6 표준에 따라 ShapeProcessor 클래스를 반드시 수정하지 않고도 새로운 모양의 영역을 설명하도록 이 기능을 확장할 수 있습니다.

다음과 같이 할 수 있습니다.

class Person {
    constructor(name, age, height, country){
      this.name = name
      this.age = age
      this.height = height
      this.country = country
  }
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

위 코드 조각에서는 확장 키워드를 사용하여 Shape 클래스의 기능을 확장했습니다. 각 하위 클래스에서는 Area() 메서드의 구현을 재정의합니다. 이 원칙에 따라 ShapeProcessor 클래스의 기능을 수정하지 않고도 더 많은 모양과 프로세스 영역을 추가할 수 있습니다.

OCP가 중요한 이유는 무엇입니까?

  • 버그 감소: OCP는 시스템 수정을 방지하여 대규모 코드 기반의 버그를 방지하는 데 도움이 됩니다.
  • 소프트웨어 적응성 장려: OCP는 또한 소스 코드를 손상시키거나 변경하지 않고도 소프트웨어에 새로운 기능을 추가할 수 있는 용이성을 향상시킵니다.
  • 새로운 기능 테스트: OCP는 수정보다 코드 확장을 촉진하여 전체 코드베이스에 영향을 주지 않고 새로운 기능을 하나의 단위로 더 쉽게 테스트할 수 있도록 해줍니다.

리스코프 대체 원칙

리스코프 대체 원칙은 서브클래스의 객체가 코드를 손상시키지 않고 슈퍼클래스의 객체를 대체할 수 있어야 한다는 것입니다. 예를 들어 이것이 어떻게 작동하는지 분석해 보겠습니다. L이 P의 하위 클래스인 경우 L의 객체는 시스템을 손상시키지 않고 P의 객체를 대체해야 합니다. 이는 서브클래스가 시스템을 손상시키지 않는 방식으로 슈퍼클래스 메서드를 재정의할 수 있어야 함을 의미합니다.

실제로는 Liskov 대체 원칙에 따라 다음 조건이 준수됩니다.

  • 하위 클래스는 코드를 손상시키지 않고 상위 클래스의 메서드를 재정의해야 합니다
  • 하위 클래스는 상위 클래스의 동작에서 벗어나서는 안 됩니다. 즉, 하위 클래스는 기능을 추가할 수만 있고 상위 클래스 기능을 변경하거나 제거할 수는 없습니다.
  • 상위 클래스의 인스턴스와 작동하는 코드는 클래스가 변경되었다는 사실을 알 필요 없이 하위 클래스의 인스턴스와 작동해야 합니다

이제 JavaScript 코드 샘플을 사용하여 Liskov 대체 원칙을 설명할 차례입니다. 살펴보세요:

class Person {
    constructor(name, dateOfBirth, height, country){
      this.name = name
      this.dateOfBirth = dateOfBirth
      this.height = height
      this.country = country
  }
}

class PersonUtils {
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}

const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); 
console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth));

class PersonService {
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

위의 코드 조각에서는 두 개의 하위 클래스(자전거와 자동차)와 하나의 슈퍼 클래스(차량)를 만들었습니다. 이 기사의 목적을 위해 우리는 슈퍼클래스에 대해 단일 메서드(OnEngine)를 구현했습니다.

LSP의 핵심 조건 중 하나는 하위 클래스가 코드를 손상시키지 않고 상위 클래스의 기능을 재정의해야 한다는 것입니다. 이를 염두에 두고 방금 본 코드 조각이 어떻게 Liskov 대체 원칙을 위반하는지 살펴보겠습니다. 실제로 자동차는 엔진이 있어서 엔진을 켤 수 있지만, 자전거는 기술적으로 엔진이 없어 엔진을 켤 수 없습니다. 따라서 Bicycle은 코드를 손상시키지 않고 Vehicle 클래스의 OnEngine 메서드를 재정의할 수 없습니다.

이제 Liskov 대체 원칙을 위반하는 코드 섹션을 확인했습니다. Car 클래스는 슈퍼클래스의 OnEngine 기능을 재정의하고 이를 다른 차량(예: 비행기)과 구별하는 방식으로 구현할 수 있으며 코드가 손상되지 않습니다. Car 클래스는 Liskov 대체 원칙을 충족합니다.

아래 코드 조각에서는 Liskov 대체 원칙을 준수하도록 코드를 구성하는 방법을 설명합니다.

class Person {
    constructor(name, age, height, country){
      this.name = name
      this.age = age
      this.height = height
      this.country = country
  }
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다음은 일반 기능인 move를 포함하는 Vehicle 클래스의 기본 예입니다. 모든 차량이 움직인다는 것이 일반적인 믿음입니다. 그들은 단지 다른 메커니즘을 통해 움직일 뿐입니다. LSP를 설명할 한 가지 방법은 move() 메서드를 재정의하고 특정 차량(예: Car)이 움직이는 방식을 묘사하는 방식으로 구현하는 것입니다.

이를 위해 다음과 같이 Vehicle 클래스를 확장하고 자동차의 움직임에 맞게 이동 메서드를 재정의하는 Car 클래스를 만들겠습니다.

class Person {
    constructor(name, dateOfBirth, height, country){
      this.name = name
      this.dateOfBirth = dateOfBirth
      this.height = height
      this.country = country
  }
}

class PersonUtils {
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}

const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); 
console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth));

class PersonService {
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

다른 하위 차량 클래스(예: 비행기)에서도 이동 메서드를 구현할 수 있습니다.

이를 수행하는 방법은 다음과 같습니다.

class Rectangle { 
  constructor(width, height) {
    this.width = width; 
    this.height = height; 
  } 
  area() { 
  return this.width * this.height; 
  } 
} 

class ShapeProcessor { 
    calculateArea(shape) { 
    if (shape instanceof Rectangle) { 
    return shape.area(); 
    } 
  }
}  
const rectangle = new Rectangle(10, 20); const shapeProcessor = new ShapeProcessor(); console.log(shapeProcessor.calculateArea(rectangle)); 
로그인 후 복사
로그인 후 복사

위의 두 가지 예에서는 상속 및 메서드 재정의와 같은 주요 개념을 설명했습니다.

주의: 하위 클래스가 상위 클래스에 이미 정의된 메서드를 구현할 수 있도록 하는 프로그래밍 기능을 메서드 재정의라고 합니다.

다음과 같이 정리하고 모든 것을 정리합시다.

class Shape {
  area() {
    console.log("Override method area in subclass");
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }

  area() {
    return this.width * this.height;
  }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }

  area() {
    return Math.PI * this.radius * this.radius;
  }
}

class ShapeProcessor {
  calculateArea(shape) {
    return shape.area();
  }
}

const rectangle = new Rectangle(20, 10);
const circle = new Circle(2);
const shapeProcessor = new ShapeProcessor();

console.log(shapeProcessor.calculateArea(rectangle));
console.log(shapeProcessor.calculateArea(circle));
로그인 후 복사
로그인 후 복사

이제 상위 클래스에서 단일 기능을 상속 및 재정의하고 요구 사항에 따라 구현하는 2개의 하위 클래스가 있습니다. 이 새로운 구현은 코드를 손상시키지 않습니다.

인터페이스 분리 원칙(ISP)

인터페이스 분리 원칙은 클라이언트가 사용하지 않는 인터페이스에 의존하도록 강요해서는 안 된다는 것입니다. 클라이언트가 필요하지 않은 메서드를 구현하도록 강요하는 거대하고 모놀리식 인터페이스를 갖기보다는 특정 클라이언트와 관련된 더 작고 더 구체적인 인터페이스를 만들기를 원합니다.

인터페이스를 간결하게 유지하면 코드 기반의 디버깅, 유지 관리, 테스트 및 확장이 더 쉬워집니다. ISP가 없으면 대규모 인터페이스의 한 부분이 변경되면 코드 베이스의 관련되지 않은 부분이 강제로 변경될 수 있으며, 이로 인해 대부분의 경우 코드 베이스의 크기에 따라 어려운 작업이 될 수 있는 코드 리팩토링을 수행하게 됩니다.

JavaScript는 Java와 같은 C 기반 프로그래밍 언어와 달리 인터페이스에 대한 기본 지원 기능이 없습니다. 그러나 JavaScript로 인터페이스를 구현하는 기술이 있습니다.

인터페이스는 클래스가 구현해야 하는 메서드 시그니처 집합입니다.

JavaScript에서는 다음과 같이 메소드 이름과 함수 서명이 있는 객체로 인터페이스를 정의합니다.

class Person {
    constructor(name, age, height, country){
      this.name = name
      this.age = age
      this.height = height
      this.country = country
  }
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

JavaScript로 인터페이스를 구현하려면 클래스를 생성하고 인터페이스에 지정된 것과 동일한 이름과 서명을 가진 메서드가 포함되어 있는지 확인하세요.

class Person {
    constructor(name, dateOfBirth, height, country){
      this.name = name
      this.dateOfBirth = dateOfBirth
      this.height = height
      this.country = country
  }
}

class PersonUtils {
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if(monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}

const person = new Person("John", new Date(1994, 11, 23), "6ft", "USA"); 
console.log("Age: " + PersonUtils.calculateAge(person.dateOfBirth));

class PersonService {
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 JavaScript에서 인터페이스를 만들고 사용하는 방법을 알아냈습니다. 다음으로 해야 할 일은 JavaScript에서 인터페이스를 분리하는 방법을 설명하여 모든 인터페이스가 어떻게 조화를 이루고 코드를 더 쉽게 유지 관리할 수 있는지 확인하는 것입니다.

다음 예에서는 프린터를 사용하여 인터페이스 분리 원칙을 설명하겠습니다.

프린터, 스캐너, 팩스가 있다고 가정하고 이러한 개체의 기능을 정의하는 인터페이스를 만들어 보겠습니다.

class Rectangle { 
  constructor(width, height) {
    this.width = width; 
    this.height = height; 
  } 
  area() { 
  return this.width * this.height; 
  } 
} 

class ShapeProcessor { 
    calculateArea(shape) { 
    if (shape instanceof Rectangle) { 
    return shape.area(); 
    } 
  }
}  
const rectangle = new Rectangle(10, 20); const shapeProcessor = new ShapeProcessor(); console.log(shapeProcessor.calculateArea(rectangle)); 
로그인 후 복사
로그인 후 복사

위 코드에서는 이러한 모든 기능을 정의하는 하나의 큰 인터페이스를 갖는 것에 대해 분리되거나 분리된 인터페이스 목록을 만들었습니다. 이러한 기능을 더 작은 부분과 보다 구체적인 인터페이스로 나누어 다양한 클라이언트가 필요한 메서드만 구현하고 다른 부분은 모두 유지할 수 있도록 합니다.

다음 단계에서는 이러한 인터페이스를 구현하는 클래스를 생성하겠습니다. 인터페이스 분리 원칙에 따라 각 클래스는 필요한 메서드만 구현합니다.

문서만 인쇄할 수 있는 기본 프린터를 구현하려면 다음과 같이 프린터 인터페이스를 통해 print() 메서드를 구현하면 됩니다.

class Shape {
  area() {
    console.log("Override method area in subclass");
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }

  area() {
    return this.width * this.height;
  }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }

  area() {
    return Math.PI * this.radius * this.radius;
  }
}

class ShapeProcessor {
  calculateArea(shape) {
    return shape.area();
  }
}

const rectangle = new Rectangle(20, 10);
const circle = new Circle(2);
const shapeProcessor = new ShapeProcessor();

console.log(shapeProcessor.calculateArea(rectangle));
console.log(shapeProcessor.calculateArea(circle));
로그인 후 복사
로그인 후 복사

이 클래스는 PrinterInterface만 구현합니다. 스캔이나 팩스 방식을 구현하지 않습니다. 인터페이스 분리 원칙에 따라 클라이언트(이 경우 Printer 클래스)는 복잡성을 줄이고 소프트웨어 성능을 향상시켰습니다.

종속성 역전 원리(DIP)

이제 마지막 원칙인 종속성 반전 원칙을 살펴보겠습니다. 이 원칙은 상위 수준 모듈(비즈니스 로직)이 하위 수준 모듈(구체)에 직접 의존하기보다는 추상화에 의존해야 한다는 것을 의미합니다. 이는 코드 종속성을 줄이는 데 도움이 되며 개발자에게 복잡한 문제 없이 더 높은 수준에서 애플리케이션을 수정하고 확장할 수 있는 유연성을 제공합니다.

종속성 역전 원칙이 직접적인 종속성보다 추상화를 선호하는 이유는 무엇입니까? 추상화를 도입하면 변경으로 인한 잠재적 영향이 줄어들고, 테스트 가능성이 향상되고(구체적인 구현 대신 추상화 모의) 코드의 유연성이 높아지기 때문입니다. 이 규칙을 사용하면 모듈식 접근 방식을 통해 소프트웨어 구성 요소를 더 쉽게 확장할 수 있으며 상위 수준 논리에 영향을 주지 않고 하위 수준 구성 요소를 수정할 수도 있습니다.

DIP를 준수하면 코드의 유지 관리, 확장 및 확장이 더 쉬워지고 코드 변경으로 인해 발생할 수 있는 버그를 막을 수 있습니다. 개발자는 클래스 간 긴밀한 결합 대신 느슨한 결합을 사용하는 것이 좋습니다. 일반적으로 팀은 직접적인 종속성보다 추상화를 우선시하는 사고방식을 수용함으로써 파급 중단을 일으키지 않고 새로운 기능을 적용 및 추가하거나 기존 구성 요소를 변경할 수 있는 민첩성을 얻게 됩니다. JavaScript에서는 다음과 같이 종속성 주입 접근 방식을 사용하여 DIP를 구현할 수 있습니다.

class Person {
    constructor(name, age, height, country){
      this.name = name
      this.age = age
      this.height = height
      this.country = country
  }
  getPersonCountry(){
    console.log(this.country)    
  }
  greetPerson(){
    console.log("Hi " + this.name)
  }
  static calculateAge(dob) { 
    const today = new Date(); 
    const birthDate = new Date(dob);

    let age = today.getFullYear() - birthDate.getFullYear(); 
    const monthDiff = today.getMonth() - birthDate.getMonth();

    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { 
      age--; 
    }
    return age; 
  } 
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

위의 기본 예에서 Application 클래스는 데이터베이스 추상화에 의존하는 상위 수준 모듈입니다. 우리는 MySQLDatabase와 MongoDBDatabase라는 두 개의 데이터베이스 클래스를 만들었습니다. 데이터베이스는 하위 수준 모듈이며 해당 인스턴스는 애플리케이션 자체를 수정하지 않고 애플리케이션 런타임에 주입됩니다.

결론

SOLID 원칙은 확장 가능하고 유지 관리가 가능하며 견고한 소프트웨어 설계를 위한 기본 구성 요소입니다. 이러한 원칙 세트는 개발자가 깔끔하고 모듈식이며 적응 가능한 코드를 작성하는 데 도움이 됩니다.

SOLID 원칙은 응집력 있는 기능, 수정 없는 확장성, 객체 대체, 인터페이스 분리, 구체적인 종속성에 대한 추상화를 촉진합니다. 버그를 방지하고 모든 이점을 누릴 수 있도록 SOLID 원칙을 코드에 통합하세요.


LogRocket: 컨텍스트를 이해하여 JavaScript 오류를 더 쉽게 디버깅합니다.

코드 디버깅은 항상 지루한 작업입니다. 하지만 오류를 더 많이 이해할수록 오류를 수정하는 것이 더 쉬워집니다.

LogRocket을 사용하면 이러한 오류를 새롭고 독특한 방식으로 이해할 수 있습니다. 당사의 프런트엔드 모니터링 솔루션은 JavaScript 프런트엔드에 대한 사용자 참여를 추적하여 오류를 초래한 사용자의 행동을 정확하게 확인할 수 있는 기능을 제공합니다.

SOLID principles for JavaScript

LogRocket은 콘솔 로그, 페이지 로드 시간, 스택 추적, 헤더 본문이 포함된 느린 네트워크 요청/응답, 브라우저 메타데이터 및 사용자 정의 로그를 기록합니다. JavaScript 코드의 영향을 이해하는 것은 결코 쉬운 일이 아닙니다!

무료로 사용해 보세요.

위 내용은 JavaScript의 견고한 원칙의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Demystifying JavaScript : 그것이하는 일과 중요한 이유 Demystifying JavaScript : 그것이하는 일과 중요한 이유 Apr 09, 2025 am 12:07 AM

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.

JavaScript의 진화 : 현재 동향과 미래 전망 JavaScript의 진화 : 현재 동향과 미래 전망 Apr 10, 2025 am 09:33 AM

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

JavaScript 엔진 : 구현 비교 JavaScript 엔진 : 구현 비교 Apr 13, 2025 am 12:05 AM

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

Python vs. JavaScript : 학습 곡선 및 사용 편의성 Python vs. JavaScript : 학습 곡선 및 사용 편의성 Apr 16, 2025 am 12:12 AM

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

JavaScript : 웹 언어의 다양성 탐색 JavaScript : 웹 언어의 다양성 탐색 Apr 11, 2025 am 12:01 AM

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법 Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법 Apr 11, 2025 am 08:22 AM

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축 Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축 Apr 11, 2025 am 08:23 AM

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지 C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지 Apr 14, 2025 am 12:05 AM

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

See all articles