Menu
Coddy logo textTech

Has-A 관계

Coddy Lua 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 70개 중 49번째.

이 코스 전반에 걸쳐, 여러분은 클래스 간에 동작을 공유하기 위해 상속을 사용해 왔습니다. Dog은 Animal의 "일종(is an)"인 것처럼 말이죠. 하지만 상속이 항상 올바른 도구인 것은 아닙니다.

때때로 객체들은 가계도를 공유하지 않습니다. 대신, 한 객체가 단순히 다른 객체를 포함합니다. 이것을 합성(composition)이라고 하며, 이는 "has-a" 관계를 모델링합니다.

자동차를 생각해 봅시다. 자동차는 엔진의 한 종류가 아닙니다. 자동차는 엔진을 가지고 있습니다. 엔진은 자동차 내부에 존재하는 별개의 객체입니다:

local Engine = {}
Engine.__index = Engine

function Engine:new(horsepower)
    local obj = {horsepower = horsepower}
    setmetatable(obj, Engine)
    return obj
end

local Car = {}
Car.__index = Car

function Car:new(model, engine)
    local obj = {
        model = model,
        engine = engine  -- Car 내부에 Engine 객체를 저장합니다
    }
    setmetatable(obj, Car)
    return obj
end

자동차를 생성할 때, 기존 엔진 객체를 해당 생성자에 전달합니다:

local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)

print(myCar.engine.horsepower)  -- 200

자동차는 엔진으로부터 상속받지 않습니다. 단순히 엔진에 대한 참조를 보유할 뿐입니다. 이는 두 클래스를 독립적으로 유지합니다. 다른 엔진으로 교체하거나, 동일한 엔진 클래스를 모터사이클에서 사용할 수도 있습니다.

컴포지션은 상속이 줄 수 없는 유연성을 제공합니다. 즉, 객체를 엄격한 계층 구조에 고정시키는 대신 부품들로부터 객체를 조립하는 방식입니다.

challenge icon

챌린지

쉬움

합성(composition)을 사용하여 컴퓨터 시스템을 구축해 봅시다! 상속 대신, Computer가 내부에 CPU가지는 "has-a" 관계를 보여주는 Computer 클래스를 만들 것입니다.

코드는 다음 세 개의 파일로 구성됩니다:

  • CPU.lua: 브랜드 이름과 GHz 단위의 속도를 저장하는 생성자 :new(brand, speed)를 가진 CPU 클래스를 만듭니다. {brand} @ {speed}GHz 형식의 문자열을 반환하는 :getInfo() 메서드를 포함하세요.
  • Computer.lua: 모델 이름과 CPU 객체를 인자로 받는 생성자 :new(model, cpu)를 가진 Computer 클래스를 만듭니다. Computer는 내부에 CPU 객체를 저장합니다(합성!). 컴퓨터의 모델과 해당 CPU의 정보를 출력하는 :describe() 메서드를 포함하세요.
  • main.lua: 모든 것을 하나로 합칩니다! CPU 브랜드, CPU 속도, 컴퓨터 모델에 대한 입력을 읽습니다. 먼저 CPU 객체를 생성한 다음, 이를 Computer 생성자에 전달합니다. 마지막으로 컴퓨터의 :describe() 메서드를 호출합니다.

세 가지 입력을 받게 됩니다:

  1. CPU 브랜드 (문자열)
  2. GHz 단위의 CPU 속도 (숫자)
  3. 컴퓨터 모델 이름 (문자열)

출력은 포함된 CPU의 정보를 포함하여 컴퓨터의 설명을 보여주어야 합니다:

Model: {model}
CPU: {brand} @ {speed}GHz

예를 들어, 입력이 Intel, 3.5, WorkStation인 경우 출력은 다음과 같아야 합니다:

Model: WorkStation
CPU: Intel @ 3.5GHz

Computer가 CPU를 상속받지 않고 단순히 CPU에 대한 참조를 보유하는 방식에 주목하세요. Computer의 :describe() 메서드는 저장된 객체를 통해 CPU의 데이터에 접근하며, 이는 합성이 어떻게 단순한 부품들로부터 복잡한 객체를 구성할 수 있게 하는지 보여줍니다!

치트 시트

객체는 합성(composition)을 통해 관계를 맺을 수 있으며, 이는 "has-a" 관계를 모델링합니다. 상속 대신 한 객체가 다른 객체를 구성 요소로 포함합니다.

엔진을 가진 자동차를 통한 합성의 예시:

local Engine = {}
Engine.__index = Engine

function Engine:new(horsepower)
    local obj = {horsepower = horsepower}
    setmetatable(obj, Engine)
    return obj
end

local Car = {}
Car.__index = Car

function Car:new(model, engine)
    local obj = {
        model = model,
        engine = engine  -- Car 내부에 Engine 객체를 저장합니다
    }
    setmetatable(obj, Car)
    return obj
end

합성된 객체 생성 및 사용:

local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)

print(myCar.engine.horsepower)  -- 200

합성은 엄격한 상속 계층 구조를 사용하는 대신 부품들로부터 객체를 조립함으로써 유연성을 제공합니다. 구성 요소들은 독립적으로 유지되며 서로 다른 클래스에서 재사용될 수 있습니다.

직접 해보기

-- main.lua
-- 구성을 사용하여 모든 것을 하나로 합치기

local CPU = require('CPU')
local Computer = require('Computer')

-- 입력 읽기
local cpuBrand = io.read()
local cpuSpeed = tonumber(io.read())
local computerModel = io.read()

-- TODO: 브랜드와 속도를 사용하여 CPU 객체 생성

-- TODO: 모델과 CPU 객체를 사용하여 Computer 객체 생성

-- TODO: 출력을 위해 컴퓨터의 describe() 메서드 호출
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨