์˜คํ•ด ์—†๋Š” ์†Œํ†ต์„ ์œ„ํ•œ ๋ช…ํ™•ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ๋งŒ๋“ค๊ธฐ

geunsuryu-wonderwall
  • #typescript
  • #interface

๋“ค์–ด๊ฐ€๋ฉฐ

์•ˆ๋…•ํ•˜์„ธ์š”. ๋…ธ๋จธ์Šค์—์„œ ๋ฐฑ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š” ์œ ๊ทผ์ˆ˜๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กฌ์Šคํ† ์–ด๊ฐ€ ์˜คํ”ˆ ๋œ์ง€๋„ ๊ฝค ์˜ค๋žœ ์‹œ๊ฐ„์ด ์ง€๋‚ฌ์Šต๋‹ˆ๋‹ค.

ํ”„๋กฌ์Šคํ† ์–ด๋Š” ์—ฌํƒ€ ๋‹ค๋ฅธ ์ปค๋จธ์Šค์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‹ค์–‘ํ•œ ์ œํ’ˆ๋“ค์„ ํŒ๋งคํ•˜๋ฉฐ, ๊ทธ ์ค‘ ๋ฐฐ์†ก์ด ํ•„์š”ํ•œ ์ œํ’ˆ๋“ค์€ ๊ตญ๊ฐ€๋ณ„/์ œํ’ˆ๋ณ„๋กœ ๋‹ค์–‘ํ•œ ๋ฐฐ์†ก๋น„ ์ •์ฑ…์„ ์ ์šฉํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์š” ์ •์ฑ…์œผ๋กœ๋Š” ๊ณ ์ • ๋ฐฐ์†ก๋น„ ์ •์ฑ… / ๋ฌด๊ฒŒ๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ… / ์ˆ˜๋Ÿ‰๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ… ๋“ฑ์ด ์žˆ๊ณ , ๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ ๋ชจ๋“ˆ์— ์ „๋žต ํŒจํ„ด์„ ์ ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ interface

๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ์„ ์œ„ํ•œ interface๋Š” ๋Œ€๋žต ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•œ ์ƒํ’ˆ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” items, ๋ฐฐ์†กํ•  ๊ตญ๊ฐ€ ์ •๋ณด์™€ ํ•จ๊ป˜, ํ•ด๋‹น ์ƒํ’ˆ๋“ค์— ์ ์šฉํ•  ๋ฐฐ์†ก ์ •์ฑ… strategy๋ฅผ ๋„˜๊ฒจ์„œ ๋ฐฐ์†ก๋น„๋ฅผ ๊ณ„์‚ฐํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

interface DeliveryItemType {
    id: number;
    weight: number;
    amount: number;
    deliveryPolicyId: number;
}

interface DeliveryFeeType {
    items: DeliveryItemType[];
    countryCode: Country;
}

class DeliveryFeeCalculator {
    calculateDeliveryFee(deliveryItems: DeliveryFeeType, strategy: Strategy<UnionDeliveryPolicy>) {
        return strategy.calculate(deliveryItems);
    }
}

๊ฐ ์ „๋žต ๊ฐ์ฒด๋“ค์€ ํ•ด๋‹น ์ •์ฑ…์— ๋งž๊ฒŒ ๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

// ์ˆ˜๋Ÿ‰๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ…
class DiffAmountRangeStrategy implements Strategy<DiffAmountRangePolicy> {
    calculate(deliveryItems: DeliveryFeeType) {
        ...
    }
}

// ๋ฌด๊ฒŒ๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ…
class DiffWeightRangeStrategy implements Strategy<DiffWeightRangePolicy> {
    calculate(deliveryItems: DeliveryFeeType) {
        ...
    }
}

์˜คํ•ด์˜ ์‹œ์ž‘

๊ทธ๋ ‡๊ฒŒ ์‹œ๊ฐ„์ด ์ง€๋‚˜๊ณ , ๋ฌด๊ฒŒ๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ… ๊ณ„์‚ฐ์— ์ถ”๊ฐ€ ๋ฐฐ์†ก๋น„๋ฅผ ๋ถ€๊ณผํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

์ „๋žต ๊ฐ์ฒด๋กœ ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ฌด๊ฒŒ๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ… class๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋ฌธ์ œ์—†์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„๊ฑฐ๋ผ ์ƒ๊ฐํ–ˆ๊ณ ,
๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋˜ DeliveryItemType ์— ์ถ”๊ฐ€ ๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ์— ํ•„์š”ํ•œ extraDeliveryPolicyId๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

export interface DeliveryItemType {
    id: number;
    weight: number; // ๋ฌด๊ฒŒ
    amount: number; // ์ˆ˜๋Ÿ‰
    deliveryPolicyId: number; // ๋ฐฐ์†ก๋น„ ์ •์ฑ…
    extraDeliveryPolicyId?: number; // ์ถ”๊ฐ€ ๋ฐฐ์†ก๋น„ ์ •์ฑ…
}

๊ทธ๋ ‡๊ฒŒ ๊ตฌํ˜„์„ ํ•˜๋Š” ์ค‘์—, ๊ธฐ์กด ์ฝ”๋“œ์—์„œ ์ƒํ’ˆ๋“ค์˜ ์ด ๋ฌด๊ฒŒ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ถ€๋ถ„์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

interface๋ฅผ ๋ณด๋ฉด, ๊ฐ ์ƒํ’ˆ ๋ณ„๋กœ weight ์™€ amount๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ƒํ’ˆ๋ณ„ ์ˆ˜๋Ÿ‰์€ ๋ฌด์‹œํ•˜๊ณ  ๋ฌด๊ฒŒ๋งŒ ๋”ํ•ด์„œ ๊ณ„์‚ฐ์„ ํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 500g ์งœ๋ฆฌ ์ƒํ’ˆ 5๊ฐœ, 300g ์งœ๋ฆฌ ์ƒํ’ˆ 3๊ฐœ๋ฅผ ์‚ฌ๋ฉด, 3400g์ด ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, 800g ์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ณ  ์žˆ์—ˆ๋˜ ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

// ๋ฌด๊ฒŒ๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ…
class DiffWeightRangeStrategy implements Strategy<DiffWeightRangePolicy> {
    calculate(deliveryItems: DeliveryFeeType) {
        const totalWeight = deliveryItems.items.reduce(
            (prev, cur) => prev + cur.weight,
            0
        )
    }
}

๊ทธ๋ž˜์„œ ๋น ์ง„ ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๋‹ˆ ๋ฐฐ์†ก๋น„๊ฐ€ ์ด์ƒํ•˜๊ฒŒ ๋งŽ์ด ๋‚˜์™”์Šต๋‹ˆ๋‹ค.

์•Œ๊ณ ๋ณด๋‹ˆ, deliveryItems๋กœ ๋„˜๊ธฐ๋Š” weight ๋Š” ์ด๋ฏธ ํ•ด๋‹น ์ƒํ’ˆ์˜ weight * amount ๋กœ ๊ณ„์‚ฐ์ด ๋๋‚œ ์ƒํƒœ๋กœ ๋„˜๊ธฐ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ฒ„๊ทธ์ธ์ค„ ์•Œ์•˜๋˜ ๋ถ€๋ถ„์ด ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹ˆ๊ณ  ๊ตฌํ˜„์€ ๋ฌธ์ œ์—†์ด ์ž˜๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœํ•˜๋Š” ๋‹น์‹œ์—๋Š” ํ•ด๋‹น interface์˜ weight ์— ์ด๋ฏธ amount๊ฐ€ ๊ณฑํ•ด์ ธ ์žˆ๋‹ค๋Š” ๊ฒƒ๊ณผ, DiffAmountRangeStrategy ์—์„œ๋Š” interface์— ์žˆ๋˜ amount๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ž˜ ์ธ์ง€ํ•˜๊ณ  ์žˆ์—ˆ์ง€๋งŒ,
์‹œ๊ฐ„์ด ํ๋ฅด๊ณ  ์ฝ”๋“œ์˜ ์ผ๋ถ€๋งŒ ๋ณด๋ฉด์„œ interface๋ฅผ ๋ดค์„๋•Œ๋Š” ๊ทธ ๊ธฐ์–ต์„ ์žƒ์–ด๋ฒ„๋ฆฐ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๋ฐฐ์†ก๋น„ ๊ณ„์‚ฐ interface

์˜คํ•ด์˜ ์†Œ์ง€๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜๋กœ ์ •์˜ํ–ˆ๋˜ interface๋ฅผ ๊ฐ ์ •์ฑ…์˜ type๋ณ„๋กœ ๋ถ„๋ฆฌํ•˜๊ณ ,
weight ๋Œ€์‹  weightSum ์ด๋ผ๋Š” ๋ช…์นญ์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

interface DeliveryFeeDiffAmountType {
    id: number;
    amount: number;
    deliveryPolicyId: number;
}

interface DeliveryFeeDiffWeightType {
    id: number;
    weightSum: number; // weight * amount
    deliveryPolicyId: number;
    extraDeliveryPolicyId: number;
}

interface UnionDeliveryFeeType {
    items: Array<DeliveryFeeDiffAmountType | DeliveryFeeDiffWeightType>;
    countryCode: Country;
}

๋ณ€๊ฒฝ๋œ interface๋ฅผ ์ ์šฉํ•œ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// deliveryItems๋ฅผ UnionDeliveryFeeType์œผ๋กœ ๋ณ€๊ฒฝ
class DeliveryFeeCalculator {
    calculateDeliveryFee(deliveryItems: UnionDeliveryFeeType, strategy: Strategy<UnionDeliveryPolicy>) {
        return strategy.calculate(deliveryItems);
    }
}

// ๋ฌด๊ฒŒ๋ณ„ ๋ฐฐ์†ก๋น„ ์ •์ฑ…
class DiffWeightRangeStrategy implements Strategy<DiffWeightRangePolicy> {
    calculate(deliveryItems: {items: DeliveryFeeDiffWeightType[]; countryCode: Country}) {
        const totalWeight = deliveryItems.items.reduce(
            (prev, cur) => prev + cur.weightSum,
            0
        )
    }
}

๊ฒฐ๋ก 

๊ฐœ๋ฐœ ๋‹น์‹œ์—๋Š” ์ž˜ ์ดํ•ดํ•˜๊ณ  ์žˆ์—ˆ๋˜ ์ฝ”๋“œ๋„ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๊ธฐ์–ต์ด ํฌ๋ฏธํ•ด์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๊ทธ ๋‹น์‹œ์—๋Š” ๋„ˆ๋ฌด๋‚˜ ๋‹น์—ฐํ•ด๋ณด์˜€๋˜ ๋กœ์ง์ด๋‚˜ ์ฝ”๋“œ๋„ ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ๋„ ๋งŽ๊ณ  ๋†“์น˜๋Š” ๋ถ€๋ถ„๋“ค๋„ ์ƒ๊ธฐ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ interface๋ฅผ ์ •์˜ํ•  ๋•Œ๋Š” ์‹œ๊ฐ„์ด ํ˜๋Ÿฌ๋„ ๋ฐ”๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด์ฃผ๋Š” ๊ฒŒ ์ค‘์š”ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์–ด์ฉ” ์ˆ˜ ์—†์ด ์ฝ”๋“œ๋งŒ์œผ๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฒฝ์šฐ์—๋Š”, ์ฃผ์„์ด๋ผ๋„ ์ž˜ ๋‚จ๊ฒจ๋†“๋Š” ๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋๊นŒ์ง€ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~ ๐Ÿ˜†

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

Art Changes Life

๋…ธ๋จธ์Šค์™€ ํ•จ๊ป˜ ์—”ํ„ฐํ…Œํฌ ์‚ฐ์—…์„ ํ˜์‹ ํ•ด๋‚˜๊ฐˆ ๋ฉค๋ฒ„๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ฑ„์šฉ ์ค‘์ธ ๊ณต๊ณ  ๋ณด๊ธฐ