카테고리 없음
[TIL]엘리스트랙 5주차 3일 - Class
NHyun
2023. 9. 6. 15:41
객체 지향 프로그래밍(OOP)란?
- OOP는 컴퓨터 프로그램을 객체(Object)의 모임으로 파악하려는 컴퓨터 프로그래밍 패러다임이다.
- 객체(Object)들은 서로 메시지를 주고 받을 수 있으며 데이터를 처리할 수 있다.
Ex) 사람을 하나의 객체라고 한다면 사람을 구성하는 뇌부터 눈,코,입,귀,팔,다리 등을 각각 나눠서 관리하고 서로 상호작용하여 결국 사람이 밥을 먹거나, 행동을 하는 등의 동작을 하도록 만드는 것.
장점
- 프로그램을 유연하고 변경이 용이하게 만든다.
- 프로그램의 개발과 보수를 간편하게 만든다.
- 직관적인 코드 분석을 가능하게 한다.
- 객체 지향 프로그래밍의 중요한 특성 - 강한 응집력(Strong Cohesion)과 약한 결합력(Loose Coupling)을 지향한다.
Class
클래스의 요소
- 필드(field)
- 생성자(constructor)
- 메서드(method)
이 3개를 통칭해 멤버(member)라고 한다.
- 인스턴스(instance): new 연산자에 의해서 생성된 객체를 뜻한다.
Ex) 위에서 사람으로 비유한 객체를 클래스에 빗대어 보면 클래스에서 필드는 눈,코,입과 같은 신체 기관, 메서드는 행동이 되는 것이다. 그리고 사람이 만들어 질 때 초기값을 넣기 위해 호출되는 것을 생성자라고 하며 이 3개를 멤버라고 한다. 인스턴스는 각각 만들어진 각각의 사람을 나타낸다.
클래스의 문법
- class 키워드를 이용해 클래스를 만들 수 있다.
- new 키워드를 통해 인스턴스를 생성할 수 있다.
- 클래스 내에서 클래스 멤버를 사용하기 위해서는 this 키워드를 사용한다.
접근 제어자
- 속성 또는 메서드로의 접근을 제한하기 위해 사용한다.
- TypeScript에는 3종류의 접근 제어자가 존재한다. => public > protected> private
- Java와 다르게 package 개념이 없어 default 접근 제어자는 존재하지 않는다.
public 접근 제어자
- 프로그램 내에서 선언된 멤버들이 자유롭게 접근할 수 있다.
- TypeScript에서 멤버는 기본적으로 public으로 선언된다.
- 명시적으로 멤버를 public으로 표시할 수도 있다.
class Animal {
public name:string
constructor(theName:string) {
this.name = theName;
}
}
new Animal("cat").name;
private 접근 제어자
- 멤버가 포함된 클래스 외부에서의 접근을 막는다.
class Animal {
private name:string
constructor(theName:string) {
this.name = theName;
}
}
new Animal("cat").name; //Error:Property 'name'is private and only accessible within class 'Animal'
일반적으로 TypeScript에서 클래스의 private 변수를 선언할 때 변수 이름 앞에 언더스코어(_)를 추가하는 것이 일반적인 관례이다.
protected 접근 제어자
- 멤버가 포함된 클래스와 그 하위 클래스 외부에서의 접근을 막는다.
- Person이 파생된 Employee의 인스턴스 메서드에서는 name을 사용할 수 있다.
상속
- OOP는 상속을 이용하여 존재하는 클래스를 확장해 새로운 클래스를 생성할 수 있다.
- extends 키워드로 Animal이라는 기초 클래스에서 Dog 클래스가 파생되었다.
- 파생된 클래스는 하위클래스(subclass), 기초 클래스는 상위클래스(superclass)라고 한다.
- Dog,Cat은 Animal의 기능(move 메서드)을 확장하기 때문에, move()와 makeDound()를 가진 인스턴스를 생성한다.
class Animal {
move(distanceInmeters: number) {
console.log('Animal moved${distanceInmeter}m.');
}
}
class Dog extends Animal {
makeSound() {
console.log('왈왈');
}
}
class Cat extends Animal {
makeSound() {
console.log("야옹");
}
}
const dog = new Dog()
dog.move(10);
dog.makeSound();
const cat = new Cat();
cat.move(5);
cat.makeSound();
Getters & Setters / readonly / static
getters & setters
- 비공개로 설정하려는 속성은 private로 설정하고, 속성값을 읽고 수정하는 getter/setter 함수를 사용한다. 즉, class의 속성에 직접 접근하는 것을 막고, getter, setter 함수를 사용해 값을 받아오거나 수정한다. - 속성에 직접 접근하여 수정하면 데이터의 무결성이 깨질 수 있다.(캡슐화 권장)
- 각 객체의 멤버에 접근하는 방법을 세밀하게 제어할 수 있다.
Class Person {
private_name:string
get name() {
return this._name;
}
set name(name:string) {
if(name:length>10) {
throw new Error("name too long")
}
this._name=name;
}
}
let person = new Person();
console.log(person.name); // undefined
person.name="june";
console.log(person.name); june;
person.name="junejunejunejunejune"; // throw Error
readonly
- 읽기만 가능한 속성으로 선언해 변경할 수 없게 만든다.
- 선언될 때나 생성자에서 값을 설정하면 이후 수정할 수 없다.
class Person {
readOnly age:number=20//선언 초기화
constructor(age:number) {
this.age=age;
}
}
let person = new Person(10); //생성자 초기화시 ok
person.age=30; //Error:Cannot assign to 'age' because it is a read-only property.
static
- 각 인스턴스가 아닌 클래스 자체에서 보이는 전역 멤버를 생성한다. // 전역 멤버: 객체마다 할당되지 않고 클래스의 모든 객체가 공유하는 멤버
- "클래스명"을 앞에 붙여서 static 멤버에 접근할 수 있다.
- 범용적으로 사용되는 값에 설정한다.
- ES6에는 메서드 전용 속성으로 선언이 안되었으나, TypeScript에서는 사용할 수 있다.
class Grid{
static origin = {x:0, y:0}
calculateDistanceFromOrigin(point:{x:number; y:number}) {
let xDist = point.x-Grid.origin.x;
let yDist = point.y-Grid.origin.y;
return Math.sqrt(xDist*xDist+*yDist*yDist)/this.scale;
}
constructor(public scale:number) {}
}
let grid1 = new Grid(1.0); //1x scale
let grid2 = new Grid(5.0); //5x scale
console.log(grid1.calculateDistanceFromOrigin({x:10,y:10}));
console.log(grid2.calculateDistanceFromOrigin({x:10,y:10}));
추상 클래스
- 추상 클래스는 다른 클래스들이 파생될 수 있는 기초 클래스이다.
- 직접 인스턴스화 할 수 없다.
- abstract 키워드는 추상 클래스나 추상 메서드를 정의하는 데 사용된다.
- 추상 메서드는 클래스에는 구현되어 있지 않고, 파생된 클래스에서 구현해야 한다.
abstract class Animal {
protected name: string
constructor(name:string) {
this.name=name;
}
abstract makeSound() : void
move(): void {
console.log("move!");
}
}
class Dog extends Animal {
constructor(name:string) {
super(name); // 파생된 클래스의 생성자는 반드시 super()를 호출
}
makeSound():void{//반드시 파생된 클래스에서 구현 필수
console.log(this.name + "멍멍");
}
}
const animal = new Animal("animal"); //Error:Cannot create an instance of an abstract class
const dog = new Dog("진돗개");
dog.makeSound(); //진돗개 멍멍
추상 클래스를 활용한 디자인 패턴(Template Method Pattern)
- 프로그램 일부분을 서브 클래스로 캡슐화해 전체 구조를 바꾸지 않고 특정 단계의 기능을 바꾸는 것을 디자인 패턴이라고 한다.
- 전체적인 알고리즘은 상위 클래스에서 구현하고 다른 부분은 하위 클래스에서 구현한다.
- 전체 구조는 유사하지만 부분적으로 다른 구문으로 구성된 메서드의 코드 중복을 최소화 할 수 있다.
abstract class parent {
//템플릿 메서드 : 자식에서 공통적으로 사용하는 부분(someMethod)
public do() {
console.log("Parent에서 실행-상"); // 1
this.hook(); //훅 메서드 Child에서 구현해야 할 부분
console.log("Parent에서 실행-하"); //3
}
abstract hook():void
}
class Child extends Parent {
hook():void {
console.log("Child"); //2
}
}
const child = new Child();
child do();
//실행 결과
//Parent에서 실행-상
//Child
//Parent에서 실행-하