Develop/Design Pattern

[ DAO, DTO, VO / Python ์—์„œ ] DAO, DTO, VO ์— ๋Œ€ํ•ด

proggg 2024. 11. 3. 19:12
728x90

Python์—์„œ DAO, DTO, VO๋ž€? ๊ฐœ๋…๊ณผ ์˜ˆ์ œ

Python์„ ๋น„๋กฏํ•œ ์—ฌ๋Ÿฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ๊ตฌ์กฐํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋””์ž์ธ ํŒจํ„ด๊ณผ ๊ฐ์ฒด ์œ ํ˜•์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ†ต์‹ ํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ DAO(Data Access Object), DTO(Data Transfer Object), VO(Value Object)์™€ ๊ฐ™์€ ๊ฐœ๋…์ด ์ž์ฃผ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ๊ฐœ๋…๊ณผ ํŠน์ง•, ๊ทธ๋ฆฌ๊ณ  Python์—์„œ์˜ ๊ตฌํ˜„ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


1. DAO (Data Access Object)

DAO๋ž€?

DAO๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ ํŒŒ์ผ ๋“ฑ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์ €์žฅํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. DAO๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ง์ ‘์ ์ธ ์ƒํ˜ธ์ž‘์šฉ์„ ๋‹ด๋‹นํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์ฝ”๋“œ์™€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

DAO์˜ ์—ญํ• 

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๋ฐ ์ข…๋ฃŒ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • CRUD ์ž‘์—… ๊ด€๋ฆฌ: Create, Read, Update, Delete์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌ: ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ๊ด€๋ฆฌ์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.

Python์—์„œ DAO ๊ตฌํ˜„ ์˜ˆ์ œ

์•„๋ž˜๋Š” User ํ…Œ์ด๋ธ”์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” UserDAO ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” SQLite๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๊ฒฐํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

import sqlite3

class UserDAO:
    def __init__(self, db_name):
        self.db_name = db_name

    def connect(self):
        return sqlite3.connect(self.db_name)

    def create_table(self):
        with self.connect() as conn:
            cursor = conn.cursor()
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS users (
                    id INTEGER PRIMARY KEY,
                    name TEXT,
                    age INTEGER
                )
            ''')
            conn.commit()

    def insert_user(self, name, age):
        with self.connect() as conn:
            cursor = conn.cursor()
            cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", (name, age))
            conn.commit()

    def get_user_by_id(self, user_id):
        with self.connect() as conn:
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
            return cursor.fetchone()

์‚ฌ์šฉ ์˜ˆ์ œ

# DAO ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์‚ฌ์šฉ
user_dao = UserDAO('test.db')
user_dao.create_table()
user_dao.insert_user('Alice', 25)

user = user_dao.get_user_by_id(1)
print(user)  # ์ถœ๋ ฅ ์˜ˆ์‹œ: (1, 'Alice', 25)

2. DTO (Data Transfer Object)

DTO๋ž€?

DTO๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ „์†กํ•˜๊ฑฐ๋‚˜ ๊ณ„์ธต ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ์ „์†กํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŠน์ • ์ปฌ๋Ÿผ ๊ฐ’๋“ค์„ ์ €์žฅํ•˜๋Š” ์šฉ๋„๋กœ ์“ฐ์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์˜ ์ €์žฅ, ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•  ๋ฟ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

DTO์˜ ์—ญํ• 

  • ๋ฐ์ดํ„ฐ ์ „๋‹ฌ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋˜๋Š” ๋‹ค๋ฅธ ๊ณ„์ธต์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ์•„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์œ ์ง€: ๋ฐ์ดํ„ฐ๋ฅผ ๋‹จ์ˆœํžˆ ์ „๋‹ฌํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ ๋กœ์ง์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ํฌํ•จํ•˜์ง€ ์•Š์Œ: DTO๋Š” ๋‹จ์ˆœํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ฒด๋กœ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜์ง€๋งŒ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Python์—์„œ DTO ๊ตฌํ˜„ ์˜ˆ์ œ

Python์—์„œ DTO๋Š” ์ฃผ๋กœ dataclass๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ด๋Š” UserDTO ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

from dataclasses import dataclass

@dataclass
class UserDTO:
    id: int
    name: str
    age: int

์‚ฌ์šฉ ์˜ˆ์ œ

# DTO ๊ฐ์ฒด ์ƒ์„ฑ
user_dto = UserDTO(id=1, name='Alice', age=25)
print(user_dto)  # ์ถœ๋ ฅ ์˜ˆ์‹œ: UserDTO(id=1, name='Alice', age=25)

3. VO (Value Object)

VO๋ž€?

VO๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์บก์Šํ™”ํ•˜์—ฌ ๋ถˆ๋ณ€์˜ ๊ฐ์ฒด๋กœ ๋‹ค๋ฃจ๋Š” ๊ฐ’ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ํŠน์ • ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์†์„ฑ๋“ค์˜ ์ง‘ํ•ฉ์ด๋ฉฐ, ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ€์ง€๋ฉด ๋™์ผํ•œ ๊ฐ์ฒด๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

VO์˜ ์—ญํ• 

  • ๊ฐ’ ์ž์ฒด๋กœ ๋™๋“ฑ์„ฑ ์ •์˜: VO๋Š” ์†์„ฑ ๊ฐ’์ด ๋™์ผํ•˜๋ฉด ๋™์ผํ•œ ๊ฐ์ฒด๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.
  • ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌ: VO๋Š” ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋„๋ก ์„ค๊ณ„ํ•˜์—ฌ ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ ํ‘œํ˜„: VO๋Š” ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ํ•„์š”ํ•œ ์ƒํƒœ๋‚˜ ๊ฐ’๋“ค์„ ์ •์˜ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Python์—์„œ VO ๊ตฌํ˜„ ์˜ˆ์ œ

VO๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐ’ ๋ณ€๊ฒฝ์„ ๋ง‰๊ธฐ ์œ„ํ•ด @dataclass(frozen=True)๋ฅผ ์‚ฌ์šฉํ•ด ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” AddressVO ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

from dataclasses import dataclass

@dataclass(frozen=True)
class AddressVO:
    street: str
    city: str
    zipcode: str

์‚ฌ์šฉ ์˜ˆ์ œ

# VO ๊ฐ์ฒด ์ƒ์„ฑ
address1 = AddressVO(street="123 Main St", city="Springfield", zipcode="12345")
address2 = AddressVO(street="123 Main St", city="Springfield", zipcode="12345")

print(address1 == address2)  # ์ถœ๋ ฅ: True (๊ฐ’์ด ๋™์ผํ•˜๋ฏ€๋กœ ๊ฐ™์€ ๊ฐ์ฒด๋กœ ๊ฐ„์ฃผ)

DAO, DTO, VO์˜ ์ฐจ์ด์  ์ •๋ฆฌ

๊ตฌ๋ถ„ DAO (Data Access Object) DTO (Data Transfer Object) VO (Value Object)
๋ชฉ์  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ ๊ด€๋ฆฌ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ์œ„ํ•œ ๊ฐ์ฒด ๋ถˆ๋ณ€์˜ ๊ฐ’ ๊ฐ์ฒด
์—ญํ•  CRUD ์ž‘์—… ์ˆ˜ํ–‰ ๋ฐ์ดํ„ฐ ๊ณ„์ธต ๊ฐ„ ์ „๋‹ฌ ๊ฐ’ ์ž์ฒด๋กœ ๋™๋“ฑ์„ฑ์„ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด
์˜ˆ์‹œ UserDAO, ProductDAO UserDTO, ProductDTO AddressVO, MoneyVO
ํŠน์ง• ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์šฉ ๊ฐ’์ด ๋™์ผํ•˜๋ฉด ๋™์ผํ•œ ๊ฐ์ฒด๋กœ ๊ฐ„์ฃผ

๊ฒฐ๋ก 

Python์—์„œ DAO, DTO, VO๋Š” ๊ฐ๊ฐ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ, ์ „์†ก, ๊ฐ’ ๊ฐ์ฒด ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ์ด๋“ค ๊ฐ์ฒด๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ, ์•ˆ์ •์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • DAO๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๋‹ด๋‹นํ•˜๋ฉฐ, CRUD ์ž‘์—…์„ ๋ถ„๋ฆฌํ•ด ์ฝ”๋“œ๋ฅผ ๋ชจ๋“ˆํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • DTO๋Š” ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ์œ„ํ•œ ๊ฐ์ฒด๋กœ์„œ, ์ฃผ๋กœ ๊ณ„์ธต ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • VO๋Š” ๊ฐ’ ์ž์ฒด๋ฅผ ์˜๋ฏธํ•˜๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ, ๊ฐ’์— ๊ธฐ๋ฐ˜ํ•œ ๋™๋“ฑ์„ฑ์„ ๊ฐ€์ง€๋ฉฐ ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด Python ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ์™€ ์ „์†ก์„ ๋”์šฑ ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

728x90