typescript에서는 변수,함수의 구조를 정의할 수 있는 interface가 존재한다. 다음과 같은 형태를 띄고 있다.
interface IBlock {
id: number;
title: string;
content: string;
date: number;
like: number;
// 옵션 체이닝으로 선택적으로 바꾼다.
hit?: number;
}
위 인터페이스를 implements 하여 객체 구조의 타입을 정할 수 있다.
const Block: IBlock = {
id: 0,
title: "제목",
content: "내용",
date: 0,
like: 0,
hit: 0,
};
? optional chaning을 통해 hit는 선택에 따라 선언이 가능해진다.
interface Discount {
// 함수만 선언
getDiscountPrice(price: number): number;
}
인터페이스에 함수를 선언하여 추상화 시켜준다. '자바' 스크립트
클래스에서 저 인터페이스를 갖고와 보자
// 가격만 수정하는 할인
class FlatDiscount implements Discount {
private amount: number;
constructor(amount: number) {
this.amount = amount;
}
getDiscountPrice(price: number): number {
return price - this.amount;
}
}
getDiscountPrice를 implement하여 갖고 왔다.
오버라이딩 하여 재정의해서 사용하면 된다.
위에 쓰인 인터페이스와 클래스를 사용하여 간단한 로그인 시스템을 구현해보자
export interface AuthProps {
email: string;
password: string;
}
export interface AuthenticationResponse {
success: boolean;
message?: string;
}
export interface Authenticator {
// 검증에 대한 요청 처리
authenticate(credentials: AuthProps): Promise<AuthenticationResponse>;
}
export interface LoginService {
// 로그인 로직에 대한 함수 구조
login(type: string, credentials: AuthProps): Promise<AuthenticationResponse>;
}
interface IEmailSender {
sendEmail(email: string): void;
}
sendEmail 즉, 유저의 이메일을 보내주는 역할을 한다. 하지만 이번 코드에는 백엔드가 없고 ,외부 api도 없으니 그냥 명시적으로 넣어놨다.
interface Strategy {
email: EmailAuthenticator;
kakao: kakaoAuthenticator;
}
이메일로 로그인 할지, 카카오로 로그인 할지 그 방법을 객체화 시켰다.
// 이메일 로그인 로직 클래스
export class EmailAuthenticator implements Authenticator {
async authenticate(credentials: AuthProps): Promise<AuthenticationResponse> {
// 로직은 없다 요청과 응답 코드가 들어갈 부분
console.log("email 로그인");
return {
success: true,
};
}
}
// 카카오 로그인 로직 클래스
export class kakaoAuthenticator implements Authenticator {
async authenticate(credentials: AuthProps): Promise<AuthenticationResponse> {
// 카카오 로그인 로직 들어갈 부분
console.log("kakao 로그인");
return { success: true };
}
}
export class Login implements LoginService {
constructor(private readonly strategy: Strategy) {}
async login(
type: "email" | "kakao",
credentials: AuthProps
): Promise<AuthenticationResponse> {
// strategy 로그인 로직이 들어있는 객체
// 여기에서 어떤 로그인 로직으로 처리할지 type구분해서
const result = await this.strategy[type].authenticate(credentials);
return result;
}
}
만약 type이 어떤 객체의 특정한 key의 value라면 그 key를 타입 부분에 명시해주면 된다.
AuthenticationResponse가 리턴 타입이므로 우린 이 로그인이 클래스에서 성공,실패 여부가 결정됨을 알 수 있다.credentials은AuthProps interface이므로 사용자가 입력한 email,password의 정보임을 알 수 있다.
class EmailSender implements IEmailSender {
sendEmail(email: string): void {}
}
원래 이메일을 보내는 로직을 오버라이딩 해야 하지만 없으므로 그저 class로 사용할 수 있도록 해주었다.
class Auth {
constructor(
private readonly authProps: AuthProps,
private readonly emailSender: EmailSender,
private readonly loginService: LoginService
) {}
public async login() {
console.log(this);
await this.loginService.login("kakao", this.authProps);
}
// 이메일 인증 처리 구조
public register(): void {
this.emailSender.sendEmail(this.authProps.email);
}
}
// 유저의 이메일과 패스워드 임시 객체
const authProps: AuthProps = { email: "2coco97@gmail.com", password: "1234" };
const _emailSender = new EmailSender();
// 이메일 로그인 로직 클래스 동적 할당
const _email = new EmailAuthenticator();
// 카카오 로그인 로직 클래스 동적할당
const _kakao = new kakaoAuthenticator();
// 로그인 서비스 로직을 가지고 있는 객체 Strategy 인터페이스 사용
const _strategy: Strategy = {
email: _email,
kakao: _kakao,
};
const _loginService = new Login(_strategy);
const auth = new Auth(authProps, _emailSender, _loginService);
auth.login();
//Auth {
// authProps: { email: '2coco97@gmail.com', password: '1234' },
// emailSender: EmailSender {},
// loginService: Login {
// strategy: { email: EmailAuthenticator {}, kakao: kakaoAuthenticator {} }
// }
//}
//kakao 로그인
// 로그인 가입 관련된 작업
import { Strategy } from "./auth";
export interface AuthProps {
email: string;
password: string;
}
export interface AuthenticationResponse {
success: boolean;
message?: string;
}
export interface Authenticator {
// 검증에 대한 요청 처리
authenticate(credentials: AuthProps): Promise<AuthenticationResponse>;
}
// 이메일 로그인 로직 클래스
export class EmailAuthenticator implements Authenticator {
async authenticate(credentials: AuthProps): Promise<AuthenticationResponse> {
// 로직은 없다 요청과 응답 코드가 들어갈 부분
console.log("email 로그인");
return {
success: true,
};
}
}
// 카카오 로그인 로직 클래스
export class kakaoAuthenticator implements Authenticator {
async authenticate(credentials: AuthProps): Promise<AuthenticationResponse> {
// 카카오 로그인 로직 들어갈 부분
console.log("kakao 로그인");
return { success: true };
}
}
// 로그인에 대한 서비스를 처리할 클래스 구조
export interface LoginService {
// 로그인 로직에 대한 함수 구조
login(type: string, credentials: AuthProps): Promise<AuthenticationResponse>;
}
// 로그인 클래스에 로그인 서비스 구조를 상속 받고
export class Login implements LoginService {
constructor(private readonly strategy: Strategy) {}
async login(
type: "email" | "kakao",
credentials: AuthProps
): Promise<AuthenticationResponse> {
// strategy 로그인 로직이 들어있는 객체
// 여기에서 어떤 로그인 로직으로 처리할지 type구분해서
const result = await this.strategy[type].authenticate(credentials);
return result;
}
}
import {
EmailAuthenticator,
Login,
AuthProps,
kakaoAuthenticator,
LoginService,
} from "./Authentication";
interface IEmailSender {
sendEmail(email: string): void;
}
class EmailSender implements IEmailSender {
sendEmail(email: string): void {}
}
export interface Strategy {
email: EmailAuthenticator;
kakao: kakaoAuthenticator;
}
class Auth {
constructor(
private readonly authProps: AuthProps,
private readonly emailSender: EmailSender,
private readonly loginService: LoginService
) {}
public async login() {
console.log(this);
await this.loginService.login("kakao", this.authProps);
}
// 이메일 인증 처리 구조
public register(): void {
this.emailSender.sendEmail(this.authProps.email);
}
}
// 유저의 이메일과 패스워드 임시 객체
const authProps: AuthProps = { email: "2coco97@gmail.com", password: "1234" };
const _emailSender = new EmailSender();
// 이메일 로그인 로직 클래스 동적 할당
const _email = new EmailAuthenticator();
// 카카오 로그인 로직 클래스 동적할당
const _kakao = new kakaoAuthenticator();
// 로그인 서비스 로직을 가지고 있는 객체 Strategy 인터페이스 사용
const _strategy: Strategy = {
email: _email,
kakao: _kakao,
};
const _loginService = new Login(_strategy);
const auth = new Auth(authProps, _emailSender, _loginService);
auth.login();
복잡하고 힘들었다.... java를 못 본지 어언1년이고 그 동안 함수지향형으로 코딩을 해서 객체지향을 보는 눈이 퇴화한것 같다 ㅜㅜ 개발자로 성장하려면 객체지향은 필수다. 더 공부해서 로그인 로직 정도는 정밀하게 설계할 수 있게 성장할 것이다.