[TIL] 24.10.21 MON

GDORI·어제
0

TIL

목록 보기
78/79
post-thumbnail

갑자기 소켓공부하다가 솔리드원칙?

식사 후 소화시키며 유튜브를 시청하다가 오랜만에 솔리드원칙 영상을 접하게 되었는데 지금까지 안 지키며 코딩했던 것 같다.
24.09.27에 작성한 TIL
다시금 정리하고 가자..

솔리드 원칙

솔리드 원칙이란 객체지향 프로그래밍과 게임 개발에 있어 중요한 코드의 유지보수성과 확장성을 높이기 위해 제안된 5가지 설계 원칙이다.

단일 책임 원칙

이름 그대로 하나의 클래스는 하나의 책임만 가진다는 원칙으로 한 클래스 내에 여러 기능을 한번에 구현하면 위배된다는 뜻이다.
플레이어가 있다면, 플레이어 안에 공격, 움직임, 스킬 등 기능을 하나의 클래스 안에 모두 넣어놓는 것이 아닌 별도의 클래스로 나누어 별도의 컴포넌트로 관리 해야한다는 것이다.

// 단일 책임 위반
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
  login() {
    console.log(`${this.email}로 로그인합니다.`);
  }
}

// 단일 책임 준수
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
}

class AuthService {
  login(user) {
    console.log(`${user.email}로 로그인합니다.`);
  }
}

개방 폐쇄 원칙

클래스가 확장에는 개방되어 있어야하고 수정에는 폐쇄되어야 한다는 원칙으로 원본 코드를 수정하지 않고 새로운 동작을 추가할 수 있어야 한다.


// 개방-폐쇄 원칙 위반
class Monster {
  attack() {
    console.log('물리 공격!');
  }
  fireAttack() {
    console.log('불 공격!');
  }
  iceAttack() {
    console.log('얼음 공격!');
  }
  
  // 기능 추가시 원본코드를 수정해야함.
}

// 개방-폐쇄 원칙 준수
class Monster {
  attack() {
    console.log('물리 공격!');
  }
}

class FireMonster extends Monster {
  attack() {
    console.log('불 공격!');
  }
}

class IceMonster extends Monster {
  attack() {
    console.log('얼음 공격!');
  }
}

리스코프 치환 원칙

바바라 리스코프가 발표한 원칙으로 파생 클래스가 기본클래스를 대체할 수 있어야 한다는 원칙이다. 부모 클래스와 자식클래스 간 이질감이 있으면 안된다는 것이다. 예를 들어 날개가 달린 동물을 Bird라고 칭할 때 fly() 메서드가 새한테는 적용이 되지만 펭귄한테는 적용될 수 없다.

// 리스코프 치환 원칙 위반
class Bird {
  fly() {
    console.log('새가 날아갑니다.');
  }
}
class Penguin extends Bird {
  fly() {
    throw new Error('펭귄은 날 수 없습니다.');
  }
}

// 리스코프 치환 원칙 준수
class Bird {
  layEggs() {
    console.log('알을 낳습니다.');
  }
}
class FlyingBird extends Bird {
  fly() {
    console.log('새가 날아갑니다.');
  }
}
class Penguin extends Bird {
  swim() {
    console.log('펭귄이 수영합니다.');
  }
}

인터페이스 분리 원칙

인터페이스를 사용할 때 작은 단위로 나누어서 사용하라는 원칙으로
한번에 많은 기능을 넣지 않는 것이 중요하다.

// 인터페이스 분리 원칙 위반
class MultiFunctionPrinter {
  print() {
    console.log('프린트합니다.');
  }

  scan() {
    console.log('스캔합니다.');
  }

  fax() {
    console.log('팩스를 보냅니다.');
  }
}

class SimplePrinter extends MultiFunctionPrinter {
  fax() {
    throw new Error('팩스 기능을 지원하지 않습니다.');
  }
}

// 인터페이스 분리 원칙 준수
class Printable {
  print() {
    console.log('프린트합니다.');
  }
}

class Scannable {
  scan() {
    console.log('스캔합니다.');
  }
}

class SimplePrinter extends Printable {}
class Scanner extends Scannable {}

의존성 역전 원칙

고수준 모듈이 저수준 모듈에서 직접적으로 가져오면 안된다는 내용으로 추상화된 인터페이스에 의존하도록 해야한다.

// 의존성 원칙 위반
class Apple {
  buy() {
    console.log('사과를 구입했습니다.');
  }
}

class Banana {
  buy() {
    console.log('바나나를 구입했습니다.');
  }
}

class FruitStore {
  constructor() {
    this.apple = new Apple();   // 사과에 직접 의존
    this.banana = new Banana(); // 바나나에 직접 의존
  }

  sellApple() {
    this.apple.buy();
  }

  sellBanana() {
    this.banana.buy();
  }
}

const store = new FruitStore();
store.sellApple();  // 사과를 구입했습니다.
store.sellBanana(); // 바나나를 구입했습니다.

// 의존성 원칙 준수

class Fruit {
  buy() {
    console.log('과일을 구입했습니다.');
  }
}

class Apple extends Fruit {
  buy() {
    console.log('사과를 구입했습니다.');
  }
}

class Banana extends Fruit {
  buy() {
    console.log('바나나를 구입했습니다.');
  }
}

class FruitStore {
  constructor(fruit) {
    this.fruit = fruit; // 어떤 과일인지 외부에서 주입
  }

  sell() {
    this.fruit.buy(); // 주입된 과일을 판매
  }
}

const apple = new Apple();
const banana = new Banana();

// 사과 가게
const appleStore = new FruitStore(apple);
appleStore.sell();  // 사과를 구입했습니다.

// 바나나 가게
const bananaStore = new FruitStore(banana);
bananaStore.sell(); // 바나나를 구입했습니다.
profile
하루 최소 1시간이라도 공부하자..

0개의 댓글