Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- Google OAuth
- spring security
- 일급 컬렉션
- builder
- java
- OAuth 2.0
- Volatile
- synchronized
- lombok
- Dependency Injection
- factory
- Spring
- 일급 객체
Archives
- Today
- Total
HJW's IT Blog
[Codeit] 6월 1주차 Study 본문
객체 지향 프로그래밍이란?
객체간의 상호작용을 중심으로 하는 프로그래밍
개념적 대상을 하나로 묶는것 → 객체
객체 안에는 무엇이 들어 있는가?
- 객체의 상태를 나타내는 변수 (유저의 아이디, 생일 등)
- 객체의 행동을 나타내는 함수 (좋아요, 상품 구매 등)
객체지향의 반대 = 절차 지향 프로그래밍
객체지향을 사용하면 보다 채계적인 프로그래밍이 가능해진다
객체지향의 주요 개념들은 다음과 같다
- Object (객체)
- Constructor Function (생성자 함수)
- Prototype (프로토타입)
- Class (클래스)
- Inheritance (상속)
- Encapsulation (캡슐화)
- Abstracton (추상화)
객체 만들기
Object-Literal
const user = {
email: 'asdf@gmail.com',
bdate: '1992-03-21';,
buy(item){
console.log(`${this.email} buys ${item.name}`);
},
};
- 위와 같이 중괄호를 쓰고 그 내부에 프로퍼티와 메소드를 나열하는 것을 object-literal 이라 부른다
- 키 - 값 쌍을 정의하여 생성하게 된다
- 객체의 간결함, 즉시 초기화, 유연성이 특징이다
Factory-Function
- 함수를 반환하는 객체
- new 키워드를 사용하지 않아도 되기 때문에 간단하며 직관적이다
- 비공개 속성과 메서드를 만들 수 있다. 이는 외부에서 객체의 속성을 직접 조작하지 못하게 하여 encapsulation 을 구현하는데에 유용하다.
const user1 = {
email: 'asdf@gmail.com',
bdate: '1992-03-21';,
buy(item){
console.log(`${this.email} buys ${item.name}`);
},
};
const user2 = {
email: 'asdf@gmail.com',
bdate: '1992-03-21';,
buy(item){
console.log(`${this.email} buys ${item.name}`);
},
};
- 위와 같은 방식은 너무 비효율적이며 코드의 양이 많아진다
function createUser(email, bdate){
const user = {
email: email,
bdate: bdate,
buy(item){
console.log(`${this.email} buys ${item.name}`);
},
};
return user;
}
const user1 = createUser('kevinheo0413@gmail.com', '1999-04-13');
const user2 = createUser('asdf@gmail.com','1999-05-11');
//아래는 encapsulation의 예제이다
function createPerson(name, age) {
let privateVariable = 'This is private';
function privateMethod() {
console.log(privateVariable);
}
return {
name: name,
age: age,
greet() {
console.log('Hello, ' + this.name);
},
showPrivate() {
privateMethod();
}
};
}
const john = createPerson('John', 30);
john.greet(); // Hello, John
john.showPrivate(); // This is private
- 함수 내부에서 전달받은 파라미터를 통해 객체를 만들고 해당 객체를 반환한다.
- 이런 형태를 factory function 이라 부른다
Constructor-Function
- 생성자 함수
function User(email, bdate){
this.email = email;
this.bdate = bdate;
this.buy = function (item) {
console.log(...);
}
}
const user1 = new User('chris123@google.com', '1999-01-01');
- 일반적인 함수와 달리 객체를 생성할 수 있는 함수이다
- Constructor Function 의 원리
- 함수 내부에 this 키워드가 생성되는 객체를 가르키게 된다
- new 가 필수
- 함수의 이름 중 첫 번째 알파벳을 보통 대문자로 할당한다
Constructor Factory
| new 키워드 필요 | new 없이 생성 가능 |
| 생성된 객체는 생성자 함수의 prototype 을 상속받는다, | 별도의 prototype 을 가지지 않으며, 객체의 메서드는 각 인스턴스마다 개별적 |
| encapsulation 을 직접 구현하기 어려움 | 클로저를 활용하여 비공개 속성과 메서드 구현이 용 |
Class
ES6 부터 지원
class User {
constructor(email, bdate){
this.email = email;
this.bdate = bdate;
}
buy(item){
console.log(item);
}
}
- 프로퍼티와 메소드의 분리
- new 키워드 필수
<aside> 💡 객체 지향 프로그래밍 언어들은 클래스 기반, 프로토타입 기반으로 나뉜다.
</aside>
객체지향 프로그래밍의 4개의 기둥
추상화, 캡슐화, 상속, 다형성을 일컫는 말.
추상화
어떠한 구체적인 존재를 원하는 방향으로 간략화 하여 나타내는 것을 의미
클래스 설계와 같은 행위도 추상화 과정에 해당
추상화의 주의점 : 프로퍼티와 메소드의 이름을 잘 지어야 한다
캡슐화
개체의 특정 프로퍼티에 직접 접근하지 못하도록 막는 행위
class User {
constructor(email, bdate){
this.email = email;
this.bdate = bdate;
}
buy(item){
console.log(`${this.email} buys ${item.name}`);
}
get email(){
return this._email;
}
set email(address){
if(address.inludes('@')){
this._email = address;
}else{
throw new Error('invalid email');
}
}
}
const user1 = new User('kevinheo0413@gmail.com', '1999-04-13');
user1.email = 'asdf@gmail.com' //setter 메소드 실행
console.log(user1.email); // getter 메소드 실행
- 위 의 set email 함수는 유저가 설정하려 할때마다 실행된다
- email 프로퍼티에 값이 설정되는것이 아닌 함수가 실행
- 이것을 setter 메소드라 한다
- 숨기고자 하는 프로퍼티의 이름 앞에 _
- 이상한 값이 email에 할당되는 것을 방지
- getter 메서드는 _email 이 아닌 email로 호출할 수 있게 해준다
- console.log(user1.email); 를 하였을 때 email 값이 바로 읽혀지는 것이 아닌 getter 를 통해 호출된다
- 하지만 위 방법은 완벽한 캡슐화가 아니다. 여전히 _email 변수를 통해 접근할 수 있기 때문인데, 이를 방지하기 위해 closure 를 사용한다
function createUser(email, birthdate) {
let _email = email;
const user = {
birthdate,
get email() {
return _email;
},
set email(address) {
if (address.includes('@')) {
_email = address;
} else {
throw new Error('invalid email address');
}
},
};
return user;
}
const user1 = createUser('chris123@google.com', '19920321');
console.log(user1.email);
- user 객체 내부에는 _email 이라는 프로퍼티가 없다.
- 하지만 그렇다고 해서 바깥의 _email변수에 접근할 수도 없기 때문에 _email 에 접근이 불가능 하다
- 함수 또한 캡슐화가 가능한데, 예제는 다음과 같다
function createUser(email, birthdate) {
const _email = email;
let _point = 0;
function increasePoint() {
_point += 1;
}
const user = {
birthdate,
get email() {
return _email;
},
get point() {
return _point;
},
buy(item) {
console.log(`${this.email} buys ${item.name}`);
increasePoint();
},
};
return user;
}
const item = {
name: '스웨터',
price: 30000,
};
const user1 = createUser('chris123@google.com', '19920321');
user1.buy(item);
user1.buy(item);
user1.buy(item);
console.log(user1.point);
- buy 함수 내부에서, 외부에 있는 increasePoint()를 실행시키는데, 이 함수 또한 user 객체를 통해 호출할 수는 없다
상속
- 하나의 객체가 다른 객체의 프로퍼티와 메소드를 물려받는 경우, 이를 상속이라 한다
class User {
constructor(email, bdate){
this.email = email;
this.bdate = bdate;
}
buy(item){
console.log(`${this.email} buys ${item.name}`);
}
}
class PremiumUser extends User {
constructor(email, bdate, level){
this.level = level;
}
streamMusicForFree(){
console.log("free music");
}
}
- extends 문법을 통해 상속받는다
- 상속의 베이스가 되는 클래스를 부모 클래스, 상속받은 클래스는 자식 클래스라 한다
- 겹치지 않는 부분만 작성하면 되어, 코드가 간결해진다
super
- 위 코드의 결과는 에러가 나오는데, 이는 파생된 자식 클래스는 super constuctor 가 필요하기 때문이다
- 자식 클래스의 constructor 내에서 super(email,bdate) 를 선언해주어야 한다
- 이 과정은 부모 클래스의 생성자 함수를 호출하는 것이다.
- super → 자식 클래스에서 부모 클래스의 요소를 호출할 때 사
다형성
- 많은 형태를 가지고 있는 성질 → 하나의 변수가 여러 종류의 객체를 가리킬 수 있는 성
- 만약 위 코드의 PremiumUser 에서 buy 메소드는 5% 할인된 가격을 결제한다고 가정하면..
- PremiumUser 내부에 동일한 이름의 메서드를 작성, 내용을 다르게 한다 → 이 과정을 overriding 이라 한다.
- 만약 여러 user 과 premium user 로 구성된 객체의 배열이 있다고 가정하고 배열을 순차적으로 도는 상황을 가정해보면
users.forEach((user) =>{
user.buy(item);
});
- 각 속한 class 에 따른 buy 가 실행된다
- 이렇게 다양한 종류의 객체를 가르킬 수 있는 것을 다형성 이라 한다
- 만약 부모 클래스의 메소드가 필요하다면?
- 자식 클래스의 매소드 내부에 super.메소드명()
instanceof 연산자
- 정확히 어느 클래스로 생성한 객체인지를 확인하고 싶을때
- 자식 클래스의 경우, 부모 클래스로 만든 객체로 인정된다
Static
- 클래스에 직접적으로 딸려있는 프로퍼티와 메소드
- 객체가 아닌 클래스 자체만으로 접근하여 사용
class Math{
static PI = 3.14;
static getCircleRadius(radius){
return Math.PI * radius * radius;
}
}
console.log(Math.PI);
console.log(Math.getCircleArea(5));