Language/Type Script

[Type Script] super 메서드와 키워드, 추상 클래스, 메서드 오버로딩, 오버로딩 생성자

나는김혜린 2022. 1. 26. 18:44

수뻐파워

 

super() 메서드와 super 키워드

슈퍼 클래스와 서브 클래스 모두 생성자가 있으면 서브의 생성자는 super() 메서드로 슈퍼의 생성자를 호출해야 한다.

Employee의 생성자는 new 연산자를 사용할 때마다 자동으로 호출되고 슈퍼 클래스 Person의 생성자 호출을 일일이 해줘야 한다.

Employee의 생성자는 네 개의 파라미터를 가지는데, department는 Employee 타입의 객체를 구성하기 위해 필요하고, 그 외 세 개의 파라미터는 Person 객체를 구성하기 위한 것이다.

super() 메서드를 호출해 Person에 전달할 수 있다.

 

슈퍼 클래스와 서브 클래스가 동일한 이름의 메서드를 가지고 있다고 가정해보자
만약 서브 클래스의 메서드가 동일한 이름을 가진 슈퍼 클래스의 메서드를 호출할 때 슈퍼 클래스의 메서드를 참조하므로 this 대신 super 키워드를 사용해야 한다.

 

reportToCompliance 메서드는 private로 선언했으므로 Employee 클래스 내부에서만 호출된다.
위 코드는 super 키워드를 활용해 슈퍼 클래스의 메서드의 기능을 재사용하는 동시에 새 기능을 추가했다.

 

추상 클래스

: 객체로 만들 수 없는 추상적인 개념, 일종의 설계도 역할을 한다.

-> abstract 키워드로 선언하고 추상 클래스로부터 객체를 생성하기 때문에 인스턴화가 불가능하고, 프로퍼티와 메서드도 abstract로 선언할 수 있다.

 

추상 클래스가 왜 필요할까?

: 구체적이지 않는 메서드를 서브 클래스에 위임해 하위에서 더 자세히 구현할 수 있다.

 

추상 클래스를 만들어보자

회사에 정규직과 계약직이 있고 고용 형태에 따라 급여 인상이 다르다.

추상 클래스 Person의 생성자에 한 개의 파라미터를 만들고, changeAddress, giveDayOff, promote 라는 메서드를 만들었다.

추상 메서드를 호출하는 명령문을 작성할 수 있지만 추상 클래스는 인스턴스화할 수 없으므로 추상 멤버는 절대로 호출되지 않는다.

인스턴스화가 가능한 추상 클래스의 자식을 생성하려면 부모의 모든 추상 메서드를 구현해야 한다.

 

Person 클래스의 자식 클래스인 Employee, Contractor 클래스를 만들고, 추상 메서드인 increasePay 메서드를 추가한다.

 

class A extends class B 구문은 클래스 A가 클래스 B를 확장한다는 뜻
클래스 A가 더 많은 프로퍼티를 가지기 때문에 클래스 B가 더 일반적이고 클래스 A가 더 상세하다.
상세한 타입은 일반적인 타입에도 사용할 수 있다.

 

정규직, 계약직을 나타내는 배열을 만들고, 반복문으로 promote() 메서드를 호출한다.
배열 workers는 Person 타입의 배열로 자식 객체의 인스턴스를 저장한다.

 

출력

[LOG]: "Giving a day off to ubin" 
[LOG]: "Increasing the hourly rate of ubin by 5%" 
[LOG]: "Giving a day off to hyerin" 
[LOG]: "Increasing the hourly rate of hyerin by 5%" 


* Person의 자식은 스스로 생성자를 선언하지 않기 때문에 Employee, Contractor가 생성될 때 부모의 생성자가 자동으로 호출되며 어느 자식도 생성자를 갖고 있지 않다면 super()로 Person의 생성자를 호출한다.

 

Person 타입의 객체의 수만큼 Person.promote()를 반복해서 호출한다.

물론, 일부는 Employee 타입이고 나머지는 Contractor 타입이다.
실제 객체 타입은 런타임 중에서만 평가되기 때문에 각 객체마다 increasePay() 사용이 가능하다.
-> 상속을 통해 기능을 확장하거나 변경하는 것을 다형성이라 한다.

 

메서드 오버로딩

: 파라미터의 유형,개수가 다르지만 이름이 같은 메서드를 여러 개 가질 수 있게 만드는 것

메서드 오버로딩의 잘못된 예

두 번째 getProdects() 함수에 중복 함수 구현 오류를 일으킨다.

ts는 오류가 있지만 js는 런타임 도중 getProducts() 메서드가 getProducts(id)로 변경되기 때문에 오류가 없다 
getProducts() 메서드를 호출하면 getProducts(id) 메서드가 호출되어 콘솔에 출력된다.

 

출력
[LOG]: "Getting the product info for 123" 
[LOG]: "Getting the product info for undefined" 

 

메서드 오버로딩의 올바른 예

getProdects(id?: number)는 구현된 메서드로 id 뒤에 물음표가 있는데,

이는 해당 파라미터를 선택사항으로 선언하는 것을 말한다.

한편 js로 생성된 코드는 getProdects(id)만 있다.

 

getProducts();
getProducts(id: number);

를 없애도 코드는 작동된다.

 

출력

[LOG]: "Getting the product info for 123" 
[LOG]: "Getting all products" 

 

파라미터 및 반환되는 타입이 서로 다른 경우

위 코드에서 getProducts() 메서드는 두 가지 방법으로 호출 가능하다.
1. product의 description을 전달하고 Product 타입인 배열을 반환함
2. product의 id를 전달하고 Product 타입인 객체를 반환함

 

출력
[LOG]: "Getting the product info for 123" 
[LOG]: "Getting product with description blue jeans" 

 

왜 굳이 오버로딩 메서드를 사용할까?

오버로딩 메서드는 ts 컴파일러가 올바른 방법으로 메서드를 호출할 수 있게 도와준다.

 

getProducts(description:string):Product[];
getProducts(id: number):Product;
-> 메서드 시그니처 선언이라 한다.
만약 이 시그니처 선언을 주석 처리하면 어떤 파라미터 타입이 어떤 타입의 값을 반환하는지 이해하기 쉽지 않다.

 

오버로딩 생성자

* 파라미터가 없는 생성자도 허용하기 때문에 생성자 구현에서 모든 파라미터를 선택할 수 있게 만듦

 

객체 속성 초기화를 위해 오버로딩 생성자가 유일한 정답은 아니다.
예를 들어 생성자에 사용되는 모든 파라미터를 나타내는 인터페이스를 선언할 수 있다.

위 코드의 인터페이스는 선택적 프로퍼티를, 클래스는 선택적 파라미터를 취하는 단일 생성자를 가진다.

오버로딩을 사용하면 여러 방법으로 메서드를 호출할 수 있지만 로직을 읽고 판단하기 힘들어질 수도 있기 때문에 사용을 절제하는 것이 일반적이다.

 

담소

추상 클래스 코드를 쓰면서 어떻게 작동되는 거지 했는데 계속 쓰다보니까 이해가 됐다.

홧팅홧팅