# OOP (Object Oriented Programming)

npm 모듈 같은거 쓰기 편한, 발명품 객체를 위주로 코드를 정리한다.

물건을 발명한다고 생각한다.

레고를 준다. 이걸 이용해서 무엇을 만들지는 창의성에 달린것이다.

**너무 깜깜해! 램프를 만들고 싶어!**

```javascript
var lamp = {
  brightness: 0, //this를 붙이지 않아도 접근 가능하다. 함수형태가 아니라서 'ㅁ'?
  turnOn: function () {
    this.brightness = 100;
  },
  turnOff: function () {
    this.brightness = 0;
  }
};

lamp.turnOn();
lamp.turnOff();
lamp.brightness = 10000000000000;
```

```javascript
function lamp() {
  var brightness = 0; // 캡슐화 지역변수로 만들었다.
  this.turnOn = function () { // 클로저로 기억한다.
    brightness = 100;
    console.log(brightness);
  };
  this.turnOff = function () {
    brightness = 0;
  }
};

var myLamp = new lamp();
myLamp.turnOn();
```

## 캡슐화(Encapsulation)

사용자가 내부정보를 접근하지 못하도록 한다.

```javascript
var lamp = (function(){
  var brightness = 0;

  return { // 클로저로 기억하고 있다. 객체로 리턴해준다. - 포인트
    turnOn: function () {
      brightness = 100;
    },
    turnOff: function () {
      brightness = 0;
    }
  }
})(); // 지역변수로 만듬

lamp.turnOn();
lamp.turnOff();
```

## 추상화(Abstraction)

소프트는 복잡할 수 있으나, 사용자는 기계안에 상세내용을 알 필요는 없다. 사용자는 간단하게 사용해야 한다.

factory 함수 - 함수를 만드는데 객체를 return하게 만든다. 생성자함수와 클래스가 아니다.

공장처럼 찍어내는 함수를 말한다.

[link](https://medium.com/javascript-scene/javascript-factory-functions-vs-constructor-functions-vs-classes-2f22ceddf33e)

현관문에 있는 램프를 만들고자 한다. 이 램프는 사용자가 간단하게 사용하면 되는거지, 이 상세내용을 알 필요는 없다.

```javascript
var lamp = (function () {
  var brightness = 0;
  return {
    turnOn: function() {
      brightness = 100;
    },
    turnOff: function() {

    },
    autoOnAndOff: function() {
      brightness = 100;
      setTimeout(function () {
        brightness = 0;
      }, 5000)
    }
  };
})();

lamp.autoOnAndOff();
```

램프가 몇 개 더 필요합니다.

**construrctor 함수를 사용하여 재사용성을 높였다**

```javascript
function Lamp () {
  this.brightness = 0; // 여기서 brightness가 노출이 되지만 재사용성을 더 중요시하여 노출시킴 
}
Lamp.prototype.turnOn = function () {
  this.brightness = 100;
};
Lamp.prototype.tyrnOff = function () {
  this.brightness = 0;
};
Lamp.prototype.autoOnAndOff = function () {
  var that = this;
  that.brightness = 100;
  setTimeout(function () {
    that.brightness = 0;
  }, 5000);
};

var lamp1 = new Lamp();
var lamp2 = new Lamp();
var lamp3 = new Lamp();
```

**Factory를 사용하여 brightness를 이용해서 brightness를 private하게 만듬**

```javascript
var lampPrototype = {
  brightness: 0,
  turnOn: function() {
    this.brightness = 100;
  },
  turnOff: function() {
    this.brightness = 0;
  },
  autoOnAndOff: function () {
    this.brightness = 100;

    setTimeout(() => {
      this.brightness = 0;
    }, 5000);
  }
};

function createLamp () {
  return Object.create(lampPrototype); // 객체를 리턴한다. 팩토리 함수다.
}

var lamp1 = createLamp();
var lamp2 = createLamp();
var lamp3 = createLamp();
```

Factory 함수란? 어떠한 함수를 만드는데 객체를 리턴하게 만든다. 그치만 이것은 생성자함수나 클래스가 아니다.

**만약 brightness를 보호하고 싶다면?**

```javascript
function createLamp () {
  var brightness = 0; // 클로저를 이용하고, 지역변수로 만든다.
  return { // 객체를 리턴한다. 팩토리함수
    turnOn: function() {
        brightness = 100;
    },
    turnOff: functi on() {
      brightness = 0;
    },
    autoOnAndOff: function () {
      brightness = 100;

      setTimeout(() => {
        brightness = 0;
      }, 5000);
    }
  };
}

var lamp1 = createLamp();
var lamp2 = createLamp();
var lamp3 = createLamp();
```

## Inheritance

**SOLID Principle**, Principle, KISS, GRASP

```javascript
function Car (owner) {
  this.owner = owner;
}

Car.prototype.soldTo = function (newOwner) {
  this.owner = newOwner;
};

var car = new Car('ken nim');
var car2 = new Car('hoho');
```

**전기차를 만들어보자**

```javascript
function ElectricCar (owner) {
  this.owner = owner;
  this.power = 0;
}

ElectricCar.prototype.soldTo = function (newOwner) {
  this.owner = newOwner;
}

ElectricCar.prototype.recharge = function (time) {
  var that = this;
  setTimeout(function () {
    that.power = Math.min((time / 100), 100);
  }, time);
};
```

Car생성자 함수와 유사한 부분이 있다.

* 주인이 존재한다.
* 양도를 한다.

자동차가 큰 카테고리에 있고 그 밑에 전기차가 있다. 행동 위임을 통해 자동차의 기능을 전기차가 사용하도록 하자.

```javascript
function ElectricCar (owner) {
  // 여기에 this는 new ElectricCar('ken'); 하면서 생성된 빈 객체의 this이다.
  // Car에 빈객체의 this를 설정하였다.
  Car.call( , owner);
  this.power = 0;
}

ElectricCar.prototype = Object.create(Car.prototype);
// console.log(ElectricCar.prototype.constructor) //car가 나온다. 
// ElectricCar.prototype = { constructor: ElectricCar };
// ElectricCar.prototype로 접근할 수 있는 프로토타입이라는 객체는 항상 constructor라는 속성을
// 가진다. 하지만 위에서 새로운 Object.create(Car.prototype);를 만들어줘서
// constructor를 잃는것이다.
ElectricCar.prototype.constructor = ElectricCar;

ElectricCar.prototype.recharge = function (time) {
  var that = this; // ec라는 reference를 생성해줬다.
  setTimeout(function () { // 함수가 끝난 후 비동기로 실행되기 때문에 this를 잃고 만다.
    that.power = Math.min((time / 100), 100); // 스코프체인을 타고 올라가서 that을 찾는다.
  }, time);
};

var ec = new ElectricCar('ken');
ec.soldto('aaa') // soldto라는게 실제 만들어놓진 않았지만 프로토타입 체인으로 사용이 가능해졌다.
```

## SOLID Principle(객체지향 설계)

객체지향 설계를 말하며, 객체지향의 다섯가지 기본 원칙을 말한다. 시간이 지나도 유지보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있다.

| 개념                                         | 설명                                   |
| ------------------------------------------ | ------------------------------------ |
| Single responsibility principle(단일 책임 원칙)  | 한 클래스는 하나의 책임만 가져야 한다.               |
| Open /  closed principle(개방 폐쇄 원칙)         | 확장에는 열려 있어야 하고 변경에는 닫혀 있어야한다.        |
| Dependency inversion principle(의존관계 역전 원칙) | 프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다.??? |
|                                            |                                      |
