1) 오버라이딩
overrriding
부모 클래스에 정의된 메서드를 자식 클래스에서 새로 구현하는 것
overridden class 오버라이든 : 부모 클래스
overridden method 오버라이든 메서드 : 자식 클래스
class Bird {
오버 라이든 클래스(부모 클래스)
// 오버라이든 메서드
flight(km : number | string ){
...}
}
class Eagle extends Bird {
(자식 클래스)
// 오버라이딩 메서드
flight(km : number){
...}
}
재정의(오버라이딩)하기 위한 조건
- 오버라이든(부모) 메서드 이름 === 오버라이딩(자식) 메서드 이름
&&
- 오버라이든(부모) 타입 ≥ 오버라이딩(자식) 타입
&&
- 오버라이든(부모) 매개변수 개수 ≥ 오버라이딩 메서드 매개변수 개수
안되는 거
//오버라이든 클래스
flight(km: number)
//오버라이딩 클래스
filght(cm : string)
=> 부모 타입이 더 넓거나 같아야 함 => flight(km: number | string)
=> 매개 변수 이름(km, cm) 달라도 상관 없음
//오버라이든 클래스
flight(km: number)
//오버라이딩 클래스
filght(cm : string, speed:number)
=> 부모 클래스 매개 변수가 더 많으면 안 됨, 부모가 더 많거나 같아야 함
예외 any
//오버라이든 클래스
flight(km: number)
// 오버라이딩 클래스
filght(km : any)
// any가 더 큰 타입이지만 어떤 타입이든 다 받을 수 있으므로 가능
2) 오버로딩
overloading 매서드의 이름은 같지만 매개변수의 타입, 개수를 다르게 정의하는 방법
- 메서드를 오버 로딩
class SingleTypeChecker {
constructor()
// 오버라이든 메서드
typeCheck(value:String) : void {
console.log(오버라이든)
}
}
class UnionTypeChecker extends SingleTypeChecker {
constructor() { super() }
// 오버로드
typeCheck(value : number) : void;
typeCheck(value : string) : void;
// 오버라이딩 메서드
typeCheck(value : number | string) : void {...}
}
함수 이름은 같지만 매개 변수 선언 형태가 다른 형태
- 인터페이스를 클래스에서 구현, 오버로딩
interface Ipoint {
getx(x:any) : any;
}
class Point implements Ipoint {
getx(x?:number|string){
if(typeof x === "number"){}
if(typeof x === "string"){}
}
}
인터페이스를 쓰면 선언 / 구현을 분리하고 구현부의 구조를 강제할 수 있음
⇒ interface (선언)
⇒ class (구현)
클래스를 상속하는 것보다 interface 를 이용하는 것이 복잡도가 낮음
2) 클래스와 인터페이스 기반 다형성 구현
다형성 여러타입을 받아들임으로써 여러 형태를 가지는 것
- 클래스의 다형성
→ 부모 클래스를 자식 클래스가 상속
→ 부모 클래스 a가 변수 타입으로 지정
→ 자식 클래스 객체에 할당 가능
→ 이때 자식 클래스가 받는 어떤 타입이든 부모 클래스가 받을 수 있음
- 인터페이스의 다형성
→ 인터페이스 a, a를 구현한 클래스 b
→ 클래스 b가 인터페이스 a타입으로 지정된 변수에 할당될 때
- 매개변수의 다형성
→ 메서드의 매개 변수가 여러 타입을 받아들이는 것 (서브 타입 타형성)
→ 타입을 지정하지 않고 여러 타입을 받아들이는 것 (매개변수 다형성)
- 클래스의 다형성
class Planet {
pubilc diameter : number;
protected isTrans : boolean = true;
getIstrans () : boolean {
return this.isTrans
}
stopTrans(): void {
console.log("stop")
this.isTrans = false
}
}
class Earth extends Planet {
pubilc feature : string[] = ["a","b","c"]
stopTrans() : void {
return this.trans = false
}
}
let earth : Planet = new Earth()
earth.feature <= 접근 불가
earth.getIstrans() true
earth.stopTrans() /* 오버라이딩 */ <- false
earth 변수는 new Earth() 를 할당 받더라도 실제 동작은 부모 클래스 기준으로 동작됨
⇒ 따라서 feature 접근 불가
⇒ 따라서 feature 접근 불가
오버라이든 메서드 보다 오버라이딩 메서드가 우선으로 호출됨
abstract class Train {
constructor(protected speed : number){
speedUp(): void {
this.speed ++;
}
}
abstract getSpeed(): number;
}
abstract Ktx extends Train {
constructor(protected speed : number){
super(speed)
}
/* 오버라이딩, 자식에서 호출, 런타임 다형성 */
pubilc getSpeed():number {
return this.speed;
}
pubilc speedUpUp():number {
return this.speed +=2;
}
}
// 부모 클래스 할당
let ktx : Train = new Ktx(300)
// 오버라이딩
ktx.getSpeed();
=> 300
ktx.speedUp();
=> 301
ktx.speedUpUp()
=> 부모에서 동작하기 때문에 접근 불가
- 인터페이스 다형성
interface IPerson {
height: number;
getAlias: ()=>string;
getAge() : number;
}
class PoliceOfficer implements Iperson {
height: number;
getAlias: ()=> "happy"
getAge() : number {
return 10;
}
hasCLub() {
return true;
}
}
let policeMan : Iperson = newPoliceOfficer();
policeMan.getAlias(); => happy
policeMan.getAge(); => 10
policeMan.hasClub(); => 접근 불가
- 매개변수 다형성
⇒ 유니언 타입
class Moniter {
display(monitor : Led | Oled) {
// if(typeof monitor === Led) {} 대신에
if(monitor instanceof Led) {
return console.log("led 모니터")
}
else (monitor instanceof Oled) {
return console.log("Oled 모니터")
}
}
}
타입이 늘어날 때마다
type MultiType = LED | Oled | Uhd
class Moniter {
display(monitor : MultiType) {
...
}
로 쓰는 건 근본적인 해결책 아님
3-1. 인터페이스 타입을 이용한 매개변수의 다형성
interface Monitor {
getName():string;
}
class Led implements Moniter {
constructor(private name: string){
getName(): string {return this.name}
}
}
class Oled implements Moniter {
constructor(private name: string){
getName(): string {return this.name}
}
class MoniterTest {
display1(monitor : Moniter) {
let myMoniter : Moniter = moniter;
return myMonitor.getName();
}
}
let displayTest = new MonitorTest()
displayTest.display1(new Led("LED TV")) => LED TV
displayTest.display1(new Oled("OLED TV")) => OLED TV
- 구현 클래스 타입은 인터페이스 타입으로 타입 호환 ⇒ 유니언 타입 대신 인터페이스
- instanceof 검사 안해도 됨 ⇒ 분기 처리/ 타입 가드 안해도 필요 없음
3) getter setter
getter 접근자
setter 설정자
class Student {
// 객체를 통해 접근할 수 없도록 private
private studentName :string;
get name(): string {
return this.studentName;
}
set name(name:string){
if(name.indexOf("happy") !== 0){
this.studentName = name;
}
}
}
let student2 = new Student()
student2.name = "happy"
=> set
student.name
=> "happy"
=> get
4) 정적 변수 / 정적 메서드
ts 는 strict 키워드 지원
클래스에 정적 변수 / 메서드 선언할 때 사용
class Circle {
// 정적 변수
static pi = 3.14
}
console.log(Circle.pi) 로 접근 가능
private static pi = 3.14
일시 접근 불가능
⇒ 공통으로 써야할 멤버가 있다면 static
4-1.싱글턴 패턴 적용
class Member {
static age = 0;
static getAge() {
return this.age;
}
private constructor()
}
let member = new Member() 처럼 인스턴스 생성불가 => private
Member.age 로 접근 가능
static 사용하면 객체 생성 없이 접근 가능
⇒ 상태 정보 담을 수 있음
⇒ 인스턴스를 만들지 못해 외부에 변수를 둘 수 없음
⇒ 외부에 변수를 두면서 객체를 유지하게 하려면 싱글턴 패턴 도입해야함
싱글턴 패턴
유일한 객체를 생성해, 공유해서 사용하는 방식
싱글턴 패턴 (부지런한 초기화 / 게으른 초기화)
부지런한 초기화
class EagerLogger {
private static uniqueObject : EagerLogger = new EagerLogger()
// private 으로 객체 생성 안되게
private EagerLogger(){}
// static 을 붙여서 외부 접근 가능하게
public static getLogger() : EagerLogger {
return this.uniqueObject
}
// 정보 로그 출력
public info(message :string) {
console.log(`[info] ${message}`)
}
}
// getLogger 를 통해 싱글턴 객체를 호출
// new 사용 불가 -> 같은 객체를 참고하고 있어서
let eagerLogger: EagerLogger = EagerLogger.getLogger();
eagerLogger.info("1번 : 경고")
=> [info] 1번 : 경고
부지런한 초기화
⇒ 프로그램이 구동할 때 초기화 일어남
⇒ 공개된 정적 메서드를 통해 생성된 객체를 얻음
⇒ 싱글턴 객체는 임이의 변수에 할당 되어 접근할 수 있음
게으른 초기화
class LazeLogger {
// 싱글턴 객체를 담는 정적 변수 선언
private static uniqueObject : LazeLogger;
// private 을 붙여서 객체로 생성 못하게
private LazeLogger(){}
public static getLogger():LazeLogger {
// 새로 생성된 객체 없으면 초기화
if(this.uniqueObject === null) {
this.uniqueObject = new LazeLogger()
}
return this.uniqueObject;
}
public info(message:string){
console.log(`[info] ${message}`)
}
}
let lazeLogger22:LazeLogger = LazeLogger.getLogger();
게으른 초기화
⇒ 프로그램이 구동할 때 초기화 x
⇒ 공개된 정적 메서드를 호출하는 시점에 객체를 생성
초기화 시점에 따라 다를 뿐
둘다
private 정적 변수를 getter를 사용해
getter 자체를 외부에서 인스턴스를 만듬
5) readOnly 제한자
⇒ readOnly 선언된 변수는 초기화되면 재할당 불가능
특정 값을 읽기 전용으로 만들 때
let literal = {readonly alias :string} = {alias:"happy"}
// 객체 리터럴 속성 앞에 지정
// 초기화를 강제로 하지 않음 => 재할당 불가능
interface Icount {
readonly count: number;
}
class TestReadOnly implements Icount {
static readonly count: number;
// 앞에 static, private, private 가능
getCount(){
this.count3 = 0; // 재할당 불가
readonly count31 = 0; // 메서드 선언 불가
}
}
function getCount () {
readonly count: number; // readonly 함수에 선언 불가
}
'TIL' 카테고리의 다른 글
타입 표명 vs 타입 단언 (0) | 2023.07.23 |
---|---|
타입스크립트 제네릭 (0) | 2023.07.23 |
클로저 (0) | 2023.06.21 |
기명함수 / 익명함수 (0) | 2023.06.21 |
api gateway (0) | 2023.06.06 |
댓글