요구사항에 맞게 코드를 작성하는 과제입니다.
1. 클래스 구조
- PublicOfficer: 추상 클래스로, 공무원의 기본 속성과 메서드를 정의
- 하위 클래스: Police, Firefighter, Doctor가 상속
2. 핵심 static 클래스들
- CentralArchives: 모든 공무원 정보를 중앙 저장소에서 관리
- TrainingCenter: 공무원 객체 생성을 담당하는 팩토리 클래스 (제네릭 활용)
- Extractor: 특정 타입의 공무원 목록을 필터링하는 유틸리티 클래스
3. 주요 기능
- 공무원 등록/제거 (CentralArchives)
- 타입별 공무원 목록 조회 (Extractor)
- 근속연수(짝수/홀수)별 필터링 기능
- 제네릭을 활용한 타입 안전성 보장
// 1. PublicOfficer 를 상속 받는 클래스를 추가하세요. (Police, Firefighter 외 1개)
// - 속성을 추가하여도 무방합니다.
// 2. CentralArchives 클래스를 static 으로 구현하세요.
// - PublicOfficer[] 를 가지고 있는 중앙 저장소입니다.
// - 해당 필드는 외부에서는 읽기만 가능해야 합니다.
// - register, remove 메소드 구현
// - PublicOfficer[] 에 추가, 삭제합니다.
// - 모든 생성되는 Officer 는 CentralArchives 에 등록되어야 합니다.
// 3. TrainingCenter 클래스를 static 으로 구현하세요.
// - PublicOfficer 를 상속받은 클래스를 생성하는 팩토리 클래스입니다.
// - Police 뿐만 아니라 다른 Class 에 대한 train 함수도 구현해야 합니다.
// 4. Extractor 클래스를 static 으로 구현하세요.
// - CentralArchives 에서 필요한 직업의 정보를 추출하는 Utility 클래스입니다.
// - getPoliceList 메소드 구현합니다. (다른 class getList 메소드도 구현해야 합니다.)
// **추가 요구 사항**
// 5. 짝수/홀수 근속연수에 따라 Officer들을 반환해주세요.
// 6. TrainingCenter와 Extractor의 중복되는 메소드를 제네릭을 활용해서 리팩토링하세요.
abstract class PublicOfficer {
public name: string;
public yearsOfService: number;
constructor(name: string, yearsOfService: number) {
// 초기화
this.name = name;
this.yearsOfService = yearsOfService;
}
public abstract introduce(): void;
public toString(): string {
return `Name: ${this.name},
Years of service: ${this.yearsOfService}`;
}
}
class Police extends PublicOfficer {
public introduce(): void {
// 필요한 구현
console.log(super.toString());
}
}
class Firefighter extends PublicOfficer {
public introduce(): void {
// 필요한 구현
console.log(super.toString());
}
}
class Doctor extends PublicOfficer {
public introduce(): void {
// 필요한 구현
console.log(super.toString());
}
}
class CentralArchives {
private static officers: PublicOfficer[] = [];
private constructor() {}
public static get allOfficers(): ReadonlyArray<PublicOfficer> {
// officers 반환
return this.officers as ReadonlyArray<PublicOfficer>;
}
public static register(officer: PublicOfficer): void {
// officer 추가
this.officers.push(officer);
}
public static remove(officer: PublicOfficer): void {
// officer 제거
const index = this.officers.indexOf(officer);
if (index > -1) {
this.officers.splice(index, 1);
}
}
}
class TrainingCenter {
private constructor() {}
public static train<T extends PublicOfficer>(
constructor: new (name: string, yearsOfService: number) => T,
name: string,
yearsOfService: number
) {
const officer = new constructor(name, yearsOfService);
CentralArchives.register(officer);
return officer;
}
}
type Constructor<T> = new (...args: any[]) => T;
class Extractor {
private constructor() {}
public static getPoliceList(): Police[] {
return this.filterByType(Police);
}
public static getFirefighterList(): Firefighter[] {
return this.filterByType(Firefighter);
}
public static getDoctorList(): Doctor[] {
return this.filterByType(Doctor);
}
private static filterByType<T extends PublicOfficer>(
type: Constructor<T>
): T[] {
// 어떤 인자를 받든 T 타입의 인스턴스를 만들 수 있는 생성자
return CentralArchives.allOfficers.filter(
(officer): officer is T => officer instanceof type
); // 이 조건문이 true를 반환하면 officer는 T 타입이다
}
// 짝수/홀수 근속연수 조회
public static filterByYearsOfService<T extends PublicOfficer>(
type: Constructor<T>,
isEven: boolean
): T[] {
return this.filterByType(type).filter((officer) =>
isEven
? this.isEvenYearsOfService(officer)
: !this.isEvenYearsOfService(officer)
);
}
public static isEvenYearsOfService(officer: PublicOfficer): boolean {
return officer.yearsOfService % 2 === 0;
}
// police
public static getPoliceEvenYearsOfService(): Police[] {
return this.filterByYearsOfService(Police, true);
}
public static getPoliceOddYearsOfService(): Police[] {
return this.filterByYearsOfService(Police, false);
}
// firefighter
public static getFirefighterEvenYearsOfService(): Firefighter[] {
return this.filterByYearsOfService(Firefighter, true);
}
public static getFirefighterOddYearsOfService(): Firefighter[] {
return this.filterByYearsOfService(Firefighter, false);
}
// doctor
public static getDoctorEvenYearsOfService(): Doctor[] {
return this.filterByYearsOfService(Doctor, true);
}
public static getDoctorOddYearsOfService(): Doctor[] {
return this.filterByYearsOfService(Doctor, false);
}
}