SOLID 원칙은 소프트웨어 작업에서 프로그래머가 소스 코드 가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩토링하여 코드 냄새를 제거하기 위해 적용할 수 있는 지침입니다.
SRP, Single Responsibility Priciple, 은 "모듈, 클래스, 함수는 하나의 책임을 가져야 한다." 라는 뜻입니다.
function addTwoNumber(num1: number, num2: number): number {
const num = num1 + num2;
console.log(num);
return num;
}
const result = addTwoNumber(1, 2);
function addTwoNumber(num1: number, num2: number): number {
const num = num1 + num2;
return num;
}
function printNumber(num: number):void {
console.log(num);
}
const result = addTwoNumber(1, 2);
printNumber(result);
class Cat {
age: number;
name: string;
constructor(age: number, name: string) {
this.age = age;
this.name = nmae;
}
eat() { /* eat */ }
walk() { /* walk */ }
speak() { /* speak */ }
print() { // Bad
console.log({
age: this.age,
name: this.name
});
}
log() { // Bad
someLogger.log(datetime.now());
}
}
class Cat {
age: number;
name: string;
constructor(age: number, name: string) {
this.age = age;
this.name = nmae;
}
eat(): void { /* eat */ }
walk(): void { /* walk */ }
speak(): void { /* speak */ }
representation(): { age: number, name: string } {
return {
age: this.age,
name: this.name
}
}
}
kitty = new Cat();
console.log(kitty.representation());
someLogger.log(kitty.representation());
OPP, Open Closed Principle, "확장에 대해서는 개방, 수정에 대해서는 폐쇄하라"라는 뜻입니다.
이는 코드에 대한 제한이 아니라, 코드 행동에 대한 원칙입니다.
class Animal {
type: string;
constructor(type: string) {
this.type = type;
}
}
function hey(animal: Animal): void {
if (animal.type === 'cat')
console.log('meow');
else if (animal.type === 'dog')
console.log('bark');
else
throw new Error('Wrong Animal.prototype.type');
}
const kity = Animal('kitty');
const bingo = Animal('Dog');
hey(kitty);
hey(bingo);
/* 새로운 Animal 이 나타나면, hey 를 수정해야 하므로...
* 새로운 extension(확장) 에 대한 새로운 Modification (수정)
* 이 필요하므로, OCP 를 위반하고 있다.
*/
class Animal() {
speak() {
throw new Error('Animal.prototype.speak must be override');
}
}
class Cat() {
speak() {
console.log('meow');
}
}
class Dog() {
speak() {
console.log('bark');
}
}
function hey(animal: Animal) {
animal.speak();
}
const cat = new Cat();
const dog = new Dog();
hey(cat);
hey(dog);
LSP, Liskov Subsititution Pricinple, 은 "Type S 가 T 의 Sub Type 일 때, object T 는 object S 로 치환 가능하다"라는 뜻입니다.
쉽게 설명하면, 부모와 자식을 변경해도 기능 상에 문제가 없어야 한다는 뜻입니다.
이를 위해서, 일관성 있는 클래스 상속관계를 유지하는 것이 중요합니다.
ISP, Interface Segregation Principle, 은 다음과 같은 뜻입니다.
1. Client 들은 사용하지도 않는 메서드들에 의존하게 만들면 안된다.
2. Big Interface 들은 Small Interfaces 로 분리하는 것이 좋다.
interface ICarBoat {
drive(): void;
turnLeft(): void;
turnRight(): void;
steer(): void;
steerLeft(): void;
steerRight(): void;
}
class Genesis implements ICarBoat {
drive() { /* logic */ }
turnLeft() { /* logic */ }
turnRight() { /* logic */ }
/* 나머지는 불피요함 */
}
interface ICar {
drive(): void;
turnLeft(): void;
turnRight(): void;
}
interface IBoat {
steer(): void;
steerLeft(): void;
steerRight(): void;
}
class SampleCarA implements ICar {}
class SampleBoatA implements IBoat {}
class SampleCarBoatA implements ICar, IBoat {}
DIP, Dependency Inversion Principle, 은 "loosely coupling software module 의 구체적인 형태" 라고 알려져 있습니다.
class Cat {
speak(): void {
console.log('meow');
}
}
class Dog {
speak(): void {
console.log('bark');
}
}
class Zoo {
cat: Cat;
dog: Dog;
constructor() {
cat = Cat();
dog = Dog();
}
}
interface Animal {
speak(): void;
}
class Cat implements Animal {
speak() {
console.log('meow');
}
}
class Dog implements Animal {
speak() {
console.log('bark');
}
}
class Zoo {
animals: Array<Animal>;
constructor(animals: Array<Animal>) {
this.animals = animals;
}
apendAnimal(animal: Animal): void {
this.animals.append(animal);
}
speakAll(): void {
for (const animal of this.animals) {
animal.speak();
}
}
}
zoo = Zoo();
zoo.addAnimal(Cat());
zoo.addAnimal(Dog());
zoo.speakAll();