본문 바로가기
Language/TypeScript

[TS] 클래스 속성과 접근제어자

by 싯벨트 2022. 11. 5.
728x90

# JavaScript - TypeScript에서 this 사용을 위한 생성자 함수 구분

  • TS에서는 this를 통해 클래스의 속성에 접근하려면 초기화 필요
    1. 생성자 함수 밖에서 초기화
    2. 생성자 함수 안에서 초기화 - 매개변수에 접근제어자 설정
// 생성자 함수 외부에서 초기화
class ClassInTS1{  
  public name: string;
  constructor(name:string){
    this.name = name
  }
}

// 생성자 함수 내부에서 초기화
class ClassInTS2{  
  constructor(public name:string){
    this.name = name
  }
}

# 접근제어자(access modifiers) - 속성

접근제어자 구분

  • public - 클래스 외부에서 접근 가능 (default 값)
  • private - 클래스 내부에서만 접근 가능(메서드명 앞에 언더바(_) 일반적인 컨벤션)
  • protected - 해당 클래스 및 자식 클래스에서만 접근 가능
class Book {
  public title:string;
  author:string;
  private _manufacturing_plant:string;
  protected paper_type:string;

  constructor(title:string, author:string, public pages:number) {
    this.title = title;
    this.author = author;
    this.pages = pages;
  }
}

let book = new Book('TS GuideBook', 'someone', 100);

접근 제어 메서드 설정

[오류발생]

 

  • book.changePaperType('인디언지')
    • protected 메서드는 Book 클래스(부모) 및 자식 클래스에서 접근 가능
  • book.setManufacturingPlant('파주 공장')
    • private 메서드는 Book 클래스(부모) 내에서만 접근 가능
class Book {

  public    title:string;
  public    author:string;
  public    pages:number = 150;
  private   _manufacturing_plant:string = '충무로 공장';
  protected paper_type:string = '밍크지';

  constructor(title:string, author:string, pages:number) {
    this.title  = title;
    this.author = author;
    this.pages  = pages;
  }

  public printPages(): string {
    return `${this.pages}페이지`;
  }

  protected changePaperType(type:string): void {
    this.paper_type = type;
  }

  private setManufacturingPlant(plant:string): void {
    this._manufacturing_plant = plant;
  }

  public setPaperType(type:string):void {
    this.changePaperType(type);
  }

  public setPlant(plant:string):void {
    this.setManufacturingPlant(plant);
  }
}

let book = new Book('TS GuideBook', 'someone', 100);
// [정상]
book.printPages();

// [오류]
book.changePaperType('인디언지');

// [오류]
book.setManufacturingPlant('파주 공장');

# 상속

전자책 클래스를 설정하는 경우

  • extends를 사용하여 Book 클래스를 상속받고
  • paper_type의 값을 다른 값으로 덮어쓸 수 있다.(오버라이딩)
  • private 속성은 자식 클래스에서 덮어쓸 수 없다.
class E_Book extends Book {
  paper_type = '스크린';
}

super() 함수 사용 -> 생성자 함수 덮어쓰기

  • 전자책에서 페이지 출력 메서드를 다운로드 여부로 변경하는 경우
class E_Book extends Book {
  paper_type = '스크린';
  constructor(
    title:string, 
    author:string, 
    pages:number, 
    public is_downloadable:boolean
  ){
    super(title, author, pages);
    this.is_downloadable = is_downloadable;
  }
}

 

# 게터/세터 (getter/ setter) 

private 속성에 접근하여 값을 읽거나 쓰기 위한 함수

  • private 속성 _species의 타입을 string | null 설정, 기본값 null 설정
  • private 속성을 읽는 (return this._species) get 함수
  • 초기화된 속성에 새로운 값을 할당하는 set 함수
    • get / set 을 앞에 붙이고, 메서드명을 동일하게 진행
class Plant {

  private _species:string|null = null;

  get species(): string {
    return this._species;
  }

  set species(value:string) {
    if ( value.length > 3 ) { this._species = value; }
  }
}

let plant = new Plant(); //null

plant.species = '줄기'; // null

plant.species = '푸른 식물'; // '푸른 식물'

# 스태틱 속성, 스태틱 메서드 (static)

인스턴스 생성없이 클래스의 속성과 메서드 사용

  • 메서드와 속성 모두 static 키워드 사용 가능
  • 클래스 내부 속성, 메서드는 this. 를 통해 사용 가능
class Mathmatics {

  static PI:number = Math.PI;

  static calcCircumference(radius:number) :number {
    return this.PI * radius * 2;
  }

  static calcCircleWidth(radius:number): number {
    return this.PI * Math.pow(radius, 2);
  }
}

let radius = 4;

let 원주율 = Mathmatics.PI;
let 넓이 = Mathmatics.calcCircleWidth(radius);
let 둘레 = Mathmatics.calcCircumference(radius);

# 추상 클래스(abstract)

클래스 앞에 abstract 표기하여 정의

  • 추상 클래스를 상속 받은 자식 클래스는 추상 메소드를 반드시 구현해야 함
  • 추상 클래스는 인스턴스 생성 불가
    • 상속 받은 클래스는 인스턴스 생성 가능
abstract class Project {

  public project_name:string|null = null;
  private budget:number = 2000000000;

  public abstract changeProjectName(name:string): void;

  public calcBudget(): number {
    return this.budget * 2;
  }
}

추상 클래스를 상속 받은 자식 클래스의 구현 및 인스턴스 형성

class WebProject extends Project {

  changeProjectName(name:string): void {
    this.project_name = name;
  }
}

let newProject = new WebProject();
console.log(newProject.project_name); // null

new_project.changeProjectName('project명 변경');
console.log(new_project.project_name); // 'project명 변경'

# 싱글턴 패턴

생성자 함수 앞에 private을 붙여서 인스턴스를 생성하는 것이 아니라 최초로 생성된 객체를 반환하도록 함

  •  생성 객체 1개로 제한

getInstance() 를 통해(조건문 설정 필요) 최초 인스턴스 형성

강점

  • 공통된 객체를 여러개 생성해서 사용해야 하는 상황

단점

  • 싱글톤 인스턴스가 너무 많은 일을 하거나 다른 클래스들 간의 결합도가 높아진다면 객제지향원칙 중, 개방-폐쇄 원칙에 위배
    • 유지보수, 테스트 어려움
    • 멀티 스레드 환경 동기화 처리를 하지 않은 경우 인스턴스 2개 생성 리스크 존재
class OnlyOne {

  private static instance: OnlyOne;

  public name:string;

  private constructor(name:string) {
    this.name = name;
  }
  
  public static getInstance() {
    if (!OnlyOne.instance) {
      OnlyOne.instance = new OnlyOne('싱글턴 객체');
    }
    return OnlyOne.instance;
  }  
}

// new 사용 불가
let bad_case = new OnlyOne('오류 발생'); // 오류

let good_case = OnlyOne.getInstance(); // 최초 인스턴스 형성

읽기전용 속성

readonly 키워드를 클래스 속성 이름 앞에 추가하면 읽기 전용 속성이 되어 다른 값을 설정할 수 없음

class Name {
  public readonly name:string;
}

참고자료