interface IBlock{
id : number
title : string
content : string
data : number
like : number
// 옵셔널체이닝 가능
hit? : number
}
const Block : IBlock = {
// 자동완성도 뜬다. 뭐가 필요한지
id : 0,
title : "",
content: "",
data : 123,
like :123,
// 옵셔널 체이닝 사용하여 hit 는 생략해도 오류없음.
hit : 123,
}
// interface 객체의 구조를 정의
interface Discount {
// 함수만 선언
getDisCountPrice(price : number) :number
}
// 가격만 수정하는 할인
// interface의 구조를 사용할 때 implements 로 사용
class FlatDiscount implements Discount {
private amount : number
//생성자 메서드
constructor(amount : number){
this.amount = amount;
}
// amount 값이 private 로 되어있기 때문에 get 메서드를 사용해서 값을 호출한다.
getDisCountPrice(price: number): number {
return price - this.amount
}
}
// 할인으로 가격 수정
class PercentDiscount implements Discount {
private amount : number;
constructor(amount : number){
this.amount = amount;
}
getDisCountPrice(price: number): number {
return price * (1 - this.amount / 100)
}
}
// 가격도 깍고 할인도 깍고
class FlatPercentDiscount implements Discount {
private flatAmount : number
private percent : number
constructor(flatAmount : number, percent : number){
this.flatAmount = flatAmount;
this.percent = percent;
}
getDisCountPrice(price: number): number {
const flatDiscountAmount = price - this.flatAmount;
return flatDiscountAmount * (1 - this.percent /100);
}
}
// 할인의 기능에 대한 유지보수가 좋아진다.
// 클래스 하나만 더 추가하면 되는것.
class Products{
private name : string
private price : number
constructor(name : string, price : number){
this.name = name;
this.price = price;
}
getName() : string {
return this.name
}
getPrice() : number{
return this.price
}
}
class ProductDiscount {
private product : Products
private discount : Discount
constructor(product : Products, discount : Discount){
this.product = product;
this. discount = discount
}
getPrice() : void{
console.log(this.discount);
console.log(this.discount.getDisCountPrice(this.product.getPrice()))
}
}
const _product = new Products("mac", 100000);
const _product2 = new Products("window", 2000);
// 10퍼 할인
const productDisCount = new PercentDiscount(10);
// 1000원 할인
const productDisCount2 = new FlatDiscount(1000);
// 1000원 빼고 10퍼할인
const productDisCount3 = new FlatPercentDiscount(1000,10);
const productWithDiscount = new ProductDiscount(_product, productDisCount);
productWithDiscount.getPrice();
productWithDiscount.getPrice(); 이 실행되면
const productWithDiscount = new ProductDiscount(_product, productDisCount);
로 생성된 클래스의 인스턴스 의 getPrice() 메서드가 실행된다.
이 코드가 실행되는 순간 이미 필드의 값은 매개변수로 전달한 _product와 ProductDisCount 로 생성이 되어
ProductDiscount {
product: Products { name: 'mac', price: 100000 },
discount: PercentDiscount { amount: 10 }
} 와 같이 생성된다.
console.log(this.discount.getDisCountPrice(this.product.getPrice())) 코드에서
this.product.getPrice())는 product의 가격을 가져오고,
this.discount 인 PercentDiscount의 인스턴스로 가서
getDisCountPrice의 메서드를 실행하고 값을 반환한다.
// 로그인 가입 관련된 작업
// 카카오, 네이버 구글
import {Strategy} from "./auth"
export interface AuthProps {
email : string
password : string
}
interface AuthenticationResponse{
success : boolean
message ? : string
}
interface Authenticator{
// (검증에 대한 요청 처리)
authenticate(credentials : AuthProps) : Promise<AuthenticationResponse>
}
// 이메일 로그인 로직 클래스
export class EmailAuthcenticator implements Authenticator {
async authenticate(credentials: AuthProps): Promise<AuthenticationResponse> {
// 로직은 없다 요청과 응답 코드가 들어갈 부분
console.log("email 로그인")
console.log(credentials);
return {success : true}
}
}
// 카카오 로그인 로직 클래스
export class KaKaoAuthenticator implements Authenticator{
async authenticate(credentials: AuthProps): Promise<AuthenticationResponse> {
// 카카오 로그인 로직 들어갈 부분
console.log("kakao 로그인")
console.log(credentials);
return {success : true}
}
}
// 로그인에 대한 서비시르르 처리할 클래스
export interface LoginService {
// 로그인 로직에 대한 함수 구조
login(type : string, credentials : AuthProps) : Promise<AuthenticationResponse>
}
// 로그인 클래스에 로그인 서비스 구조를 상속 받고
export class Login implements LoginService{
// strategy 타입을 추가해줘야 함
constructor(private readonly strategy : Strategy){}
async login(type: "email" | "kakaoo", credentials: AuthProps): Promise<AuthenticationResponse> {
// strategy 로그인 로직이 들어있는 객체
// 여기에서 어떤 로그인 로직으로 처리할지 type 구분해서
console.log(this.strategy);
console.log(this.strategy.email);
const result = await this.strategy[type].authenticate(credentials)
console.log("-------------",result);
return result
}
}
import {EmailAuthcenticator,KaKaoAuthenticator,AuthProps,Login,LoginService} from "./Authent"
// I 를 붙이는이유 인터페이스라고 표시하려고
interface IEmailSender {
sendEmail(email : string) : void
}
class EmailSender implements IEmailSender {
sendEmail(email: string): void {
}
}
export interface Strategy{
email : EmailAuthcenticator
kakaoo : KaKaoAuthenticator
}
class Auth{
// private 키워드가 붙어서 생성자에 넘겨받은 값이 객체의 키로 추가된다.
constructor(
private readonly authProps: AuthProps,
private readonly emailSender: EmailSender,
private readonly loginService : LoginService
){}
// 로그인 로직
public async login(){
console.log(this);
const aa= await this.loginService.login("kakaoo",this.authProps);
console.log("---------aa",aa);
}
// 이메일 인증 처리 구조
public register(): void {
this.emailSender.sendEmail(this.authProps.email);
}
}
// 유저의 email과 password 임시 객체
const authProps : AuthProps = {email: "soon@naver.com", password : "1234"}
const _emailSender = new EmailSender();
// email 로그인 로직 클래스 동적 할당
const _email = new EmailAuthcenticator()
// kakao 로그인 로직 클래스 동적 할당
const _kakao = new KaKaoAuthenticator()
// 로그인 서비스 로직을 가지고 있는 객체
const _strategy : Strategy = {
email : _email,
kakaoo : _kakao,
}
const _loginService = new Login(_strategy)
const auth = new Auth(authProps, _emailSender, _loginService);
console.log(auth);
auth.login();
auth.login() 로 Auth 클래스의 login 함수가 실행되는데,
const auth = new Auth(authProps, _emailSender, _loginService) 로
authProps 에는 {email: "soon@naver.com", password : "1234"},
_emailSender 에는 sendEmail(email: string): void {}
_loginService에는 {
email : _email,
kakaoo : _kakao,
} 생성자를 가진 Login 클래스의 새 인스턴스,
를 가진 Auth 클래스의 새 인스턴스가 생성된다.
login()의 함수 this.loginService.login("email",this.authProps)에 의해
Login 클래스의 login 함수가 실행되고 type은 "email" , credentials 에는 {email: "soon@naver.com", password : "1234"} 가 전달된다.
그리고 const result = await this.strategy[type].authenticate(credentials) 에 의해 EmailAuthcenticator의 authenticate() 함수가 실행된다.
그래서 console.log("email 로그인")와 console.log(credentials); 코드가 실행되어
email 로그인
{ email: 'soon@naver.com', password: '1234' } 가 출력되고, result에 { success: true } 가 반환되고,
그게 또 aa로 반환되어 출력된다.
Login 클래스에서 const result = await this.strategy[type].authenticate(credentials);
strategy의 값이 { email: EmailAuthcenticator {}, kakaoo: KaKaoAuthenticator {} } 이것인데,
호출할 때 this.strategy.type이 아닌 this.strategy[type]로 호출하는게 이해가 되지 않았다.
type은 console.log 로 출력해보면 email 또는 kakaoo 가 들어가고,
결국 this.strategy.email 이나 this.strategy.kakaoo 가 되는것인데 말이다.
하지만, this.strategy.type로 코드를 작성했을 경우 strategy에 속성명 type이 정의되어 있지 않다고 오류가 발생했고,
this.strategy.email을 console.log로 출력해보고 정상적으로 출력이 되는것을 보고 이해를 했다.
⭐⭐⭐⭐⭐⭐⭐
아 ~ 속성명을 그대로 입력하는 경우에는 .으로 접근이 가능하지만,
동적으로 어느 변수에 값을 담아서 접근하는경우에는 .이 아닌 []를 통해서 접근해야 한다는 것을...