header wave

Post

TS) 클래스와 싱글톤

2022-09-25 AM 05/06
#typescript
#study


리마인드

  • 객체 지향 언어는 멤버 변수로 클래스를 선언할 수 있다.
  • 자바스크립트 내 클래스를 생성할 수 있으며, 클래스 내 생성자(constructor)는 한 번만 실행된다.
  • 컴파일 타겟이 ES5인 경우 타입스크립트 컴파일러는 클래스를 자바스크립트 생성자 함수로 변경한다. ES6 이상이면 자바스크립트 클래스로 컴파일 된다.
  • 클래스 생성자의 파라미터를 readonly, public, protected, private 키워드로 정의하면 타입스크립트는 각 파라미터에 대한 클래스 프로퍼티를 만든다.

1. 클래스의 상속

상속이란, 물려 받는 것을 의미한다.

image

위 코드에서 Person은 슈퍼클래스, 그리고 Employee란 서브 클래스가 있다.

하위 클래스 Employee는 슈퍼클래스 Person으로 부터의 모든 프로퍼티를 상속받으므로 새로 생성된 empl 인스턴스에서 위처럼 모든 프로퍼티가 자동완성 된다.

프로퍼티 뿐만 아니라, private 키워드가 없는 메서드도 상속될 수 있다.

아래처럼 isAdult란 슈퍼클래스의 메서드도 상속된다.

image

클래스 프로퍼티와 메서드를 제어하려면?

  1. public

클래스 요소의 기본값이며, 어디서든 접근 가능하게 만드는 키워드다.

class Greeter {
  public greet() {
    console.log("hi!");
  }
}
const g = new Greeter();
g.greet();
  1. protected

서브클래스에서만 슈퍼클래스의 메서드를 불러올 수 있다. (하위 인스턴스에서는 불러올 수 없다.)

class Greeter {
  public greet() {
    console.log("Hello, " + this.getName());
  }
  protected getName() {
    return "hi";
  }
}
 
class SpecialGreeter extends Greeter {
  public howdy() {
    // OK to access protected member here
    console.log("Howdy, " + this.getName());
  }
}
const g = new SpecialGreeter();
g.greet(); // OK
g.getName();
Property 'getName' is protected and only accessible within class 'Greeter' and its subclasses.

protected 의 노출

class Base {
  protected m = 10;
}
class Derived extends Base {
  // No modifier, so default is 'public'
  m = 15;
}
const d = new Derived();
console.log(d.m); // OK

Derived 에서 m이 public으로 정의되므로 인스턴스에서 m을 호출해도 괜찮다.

Cross-hierarchy protected access

class Base {
  protected x: number = 1;
}
class Derived1 extends Base {
  protected x: number = 5;
}
class Derived2 extends Base {
  f1(other: Derived2) {
    other.x = 10;
  }
  f2(other: Base) {
    other.x = 10;
// Property 'x' is protected and only accessible through an 
// instance of class 'Derived2'. This is an instance of class 'Base'.
  }
}

오로지 서브클래스에서만 x에 대한 접근이 허용된다.

  1. private

protected와 비슷하지만, private는 오로지 슈퍼클래스 내에서만 해당 프로퍼티를 호출할 수 있다.

class Base {
  private x = 0;
}
const b = new Base();
// Can't access from outside the class
console.log(b.x);
Property 'x' is private and only accessible within class 'Base'.

class Derived extends Base {
  showX() {
    // Can't access in subclasses
    console.log(this.x);
Property 'x' is private and only accessible within class 'Base'.
  }
}

class Base {
  private x = 0;
}
class Derived extends Base {
Class 'Derived' incorrectly extends base class 'Base'.
  Property 'x' is private in type 'Base' but not in type 'Derived'.
  x = 1;
}

private 프로퍼티를 전달하는 방법

class A {
  private x = 10;
 
  public sameAs(other: A) {
    // No error
    return other.x === this.x;
  }
}

고정 변수와 싱글톤

example)

class Shooter {
	static totalBullets: 1000;

	fire() {
		Shooter.totalBullets--;
		console.log(`남은 총알 ${Shooter.totalBullets}`)
	}
}

const s1 = new Shooter();
s1.shoot();

const s2 = new Shooter();
s2.shoot();

shooter 클래스의 두 인스턴스는 동일한 totalBulltets를 공유한다.

static인 클래스멤버는 서브 클래스에 공유되지 않는다.

class Gangsta {
    static totalBullets = 100;

    shoot() {
        Gangsta.totalBullets--;
        console.log(`[G] Bullets left: ${Gangsta.totalBullets}`);
    }
}

class SuperGangsta extends Gangsta {
    shootMany() {
        SuperGangsta.totalBullets--;
        SuperGangsta.totalBullets--;
        console.log(`[SG] Bullets left: ${SuperGangsta.totalBullets}`);
    }
}

const sg = new SuperGangsta();

sg.shootMany(); // prints 98
sg.shoot();     // prints 99

싱글톤 패턴

단 하나의 인스턴스를 생성하는 디자인 패턴을 싱글톤이라고 한다.

class AppState {

    counter = 0;  // the app state
    private static instanceRef: AppState;

    private constructor() { }

    static getInstance(): AppState {
        if (AppState.instanceRef === undefined) {
            AppState.instanceRef = new AppState();
        } 

        return AppState.instanceRef; 
    }
}

// const appState = new AppState(); // error because of the private constructor

const appState1 = AppState.getInstance(); 

const appState2 = AppState.getInstance();

appState1.counter++;
appState1.counter++;
appState2.counter++;
appState2.counter++;

console.log(appState1.counter); // prints 4
console.log(appState2.counter); // prints 4

AppState 클래스는 private 생성자가 있으므로, new 키워드로 인스턴스를 생성할 수 없다.