# SOLID & Design Pattern Sample

## SOLID

- SOLID 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 제거하기 위해 적용할 수 있는 지침이다.
- 각 항목별 before & after 를 비교하면서 어떤 차이가 있는지 생각해본다.
- before & after 에 새로운, 또는 동일한 규칙(비즈니스 로직, 유효성 검사 등)을 적용해야 한다고 가정하고 변경을 시도해본다.

### SRP(Single Responsibility Principle)

- 단일 책임 원칙
- 한 클래스는 하나의 책임만 가져야 한다. 즉, 한 클래스가 변경되는 이유는 한 가지여야 한다.

#### 구현 요구사항

- 예금주의 이름으로 계좌를 생성할 수 있다.
- 계좌에 입금할 수 있다.
- 계좌에서 출금할 수 있다.

### OCP(Open/Closed Principle)

- 개방-폐쇄 원칙
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.

#### 구현 요구사항

- 최초의 결제방식은 현금, 카드 두 가지가 있다.
- 쿠폰 결제방식을 추가한다고 가정한다.
- 쿠폰으로 결제할 경우 잔고가 차감되지 않는다.

### LSP(Liskov Substitution Principle)

- 리스코프 치환 원칙
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

#### 구현 요구사항

- 좌표를 입력하면 해당 좌표로 이동수단의 위치가 변한다.

### ISP(Interface Segregation Principle)

- 인터페이스 분리 원칙
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.

#### 구현 요구사항

- 영화 상영관 좌석 현황을 조회할 수 있다.
- 영화표 예매를 진행할 수 있다.

### DIP(Dependency Inversion Principle)

- 의존 역전 원칙
- 프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙을 따르는 방법 중 하나다.

#### 구현 요구사항

- 저장소에서 파일 데이터를 불러올 수 있다.
- 하나의 저장소만 사용하며 저장소의 타입은 언제든지 변경될 수 있다.
- 각각의 저장소는 각자만의 파일 데이터 조회 요청 인터페이스를 제공한다.
    - 아마존에서는 파일 이름을 요구한다.
    - 구글에서는 파일 번호를 요구한다.

## Design Pattern

### 전략(Strategy) 패턴

#### 구현 요구사항

- 연령대별로 물건의 할인된 금액 계산기를 구현한다.
    - 아이일 경우 할인율은 15%이다.
    - 어른일 경우 할인율은 30%이다.

### 템플릿 메서드(Template Method) 패턴

#### 구현 요구사항

- 스포츠 강사를 구현한다.
    - 모든 강사는 강의가 시작할 때 스트레칭을 한다.
    - 모든 강사는 강의가 끝날 때 인사한다.
    - 수영 강사는 강의 중간에 수영 동작을 보여준다.
    - 축구 강사는 강의 중간에 축구 동작을 보여준다.

### 상태(State) 패턴

#### 구현 요구사항

- 상태별로 다르게 움직이는 게임 캐릭터를 구현한다.
    - 기본적으로 게임 캐릭터는 정지상태이다.
    - 정지 상태에서 버튼을 누르면 이동한다.
    - 이동하는 상태에서 버튼을 누르면 점프한다.
    - 점프하는 상태에서 버튼을 누르면 착지한 뒤 정지한다.
    - 게임 캐릭터는 버튼을 누르면 동작하는 상태로 스스로의 상태를 변경한다.

### 데코레이터(Decorator) 패턴

#### 구현 요구사항

- 용사는 검을 가진다.
- 용사는 검을 바꿀 수 있다.
- 검에는 속성이 부여될 수 있으며, 속성에 따라 공격이 변한다.
- 용사가 공격하면 소지한 무기의 공격이 발동된다.

### 프록시(Proxy) 패턴

#### 구현 요구사항

- 지갑의 주인은 지갑에 대해 입금 또는 출금을 진행할 수 있다.
- 지갑의 동작은 입금 및 출금만 가능하도록 제한된다.
- 지갑에 대해 입금 또는 출금이 이루어질 때 메시지를 출력한다.

### 어댑터(Adapter) 패턴

#### 구현 요구사항

- 발전소는 정해진 요청 규격에 따라 전기를 생산한다.
- 가정은 정해진 규격에 따라 전기를 얻는다.
- 발전소와 가정에서 사용하는 전기는 각각 다르다.
- 발전소에서 생산한 전기를 가정용으로 변환하는 계산식은 아래와 같다.
    - 생산된 전류량 * (발전소 전압 / 가정용 전압)
    - 발전소에서 생산한 전기의 전압은 11000V 이다.
    - 가정에서 사용하는 전기의 전압은 220V 이다.

### 옵저버(Observer) 패턴

#### 구현 요구사항

- 주문의 상태가 변경되면 배송팀과 운영팀에 알리고, 각각의 팀은 그에 따른 조치를 취한다.
    - 배송팀은 배송을 시작한다.
    - 운영팀은 고객에게 메시지를 전송한다.
- 배송팀과 운영팀 외에 다른 팀에도 필요하다면 또 다른 팀에 메시지를 전송해야 할 수도 있다.

### 미디에이터(Mediator) 패턴

#### 구현 요구사항

- 가전제품의 전원을 제어한다.
- 가전제품의 전원은 하나만 켤 수 있고, 하나를 켜면 나머지는 모두 꺼진다.
- 가전제품을 켤 경우, 해당 가전제품의 이름을 메시지로 전송한다.

### 파사드(Facade) 패턴

#### 구현 요구사항

- 회원의 모든 정보를 조회한다.
- 회원의 모든 정보에는 회원의 기본 정보와 친구들에 대한 정보가 있다.
    - 회원의 기본 정보에는 이름, 나이가 있다.
    - 회원의 친구 정보에는 친구의 이름, 나이가 있다.

### 추상 팩토리(Abstract Factory) 패턴

#### 구현 요구사항

- 과일 이름을 입력하면 해당 과일 또는 과일주스를 만들어주는 마법이 있다.
- 과일의 종류는 사과, 바나나, 오렌지로 총 세 가지다.
- 과일주스의 종류도 마찬가지로 사과주스, 바나나주스, 오렌즈주스로 총 세 가지다.

### 컴포지트(Composite) 패턴

#### 구현 요구사항

- 프랜차이즈 기업의 정산은 가맹점으로 가입된 모든 가게들의 정산을 포함한다.
- 프랜차이즈 기업은 다른 프랜차이즈 기업을 포함할 수 있다.
- 프랜차이즈 기업은 이름을 갖는다.
- 프랜차이즈 가맹점은 이름을 갖는다.

### 널 객체(Null Object) 패턴

#### 구현 요구사항

- 식당에서는 직원을 이름으로 관리하며 동명이인은 없다고 가정한다.
- 이름으로 직원을 찾을 수 있고, 해당 직원에게 근무일자를 할당할 수 있다.
- 직원은 근무일자를 고지 받으면 해당 날짜를 기억한다.

## 참고자료

- [SOLID (객체 지향 설계)](https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84)) 


