강의노트 09. [객체지향] oop (is-a, has-a, 객체합성)

|

패스트캠퍼스 컴퓨터공학 입문 수업을 듣고 중요한 내용을 정리했습니다. 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.

객체지향 용어

  • Class: 클래스를 통하여 새로운 자료형을 직접 정의한다.
  • Object: 가장 기초적인 자료형. 혹은 어떤 자료형의 인스턴스
  • Instance: 어떤 클래스를 통하여 생성된 객체는 해당 클래스의 인스턴스
  • def: 클래스 안에서 함수를 정의(define)하는 방법
  • self: 클래스 함수 안에서 쓰임. 접근한 인스턴스/객체를 가리키는 변수
  • Inheritance: 한 클래스가 다른 클래스의 특성(trait)을 상속
  • Composition: 한 클래스를 다른 클래스의 일부로 합성할 수 있음
  • is-a: notebook is a computer. 한 항목이 다른 항목을 상속
  • has-a: 한 항목이 다른 항목을 합성했거나 어떤 특성을 가졌다. 요즘은 이 경우에 객체합성을 사용

수업내용

목차

  • 상속
    • is-a (상속)
    • has-a (상속 X)
      • 지금은 안쓰지만 예전 코드를 이해하려면 알아야한다.
      • 객체합성으로 대체 및 해결한다. (아주 과거에는 상속으로 해결했다)
  • 함수 오버로딩, 오버라이딩 (아주 중요)
  • class member의 쓰임
  • 추상 클래스의 목적과 쓰임 (생각보다 많이 쓰임)
  • 정보은닉 (information hiding)
  • 캡술화 (encapsulation)
  • 절차지향에서 객체지향으로 (oop porting 과제)
  • 다형성 (polymorphism) - 파이썬만으로 다형성을 이해하면 오해의 여지가 큼 (C++ 예시로 학습)

상속 : is-a (아주 중요)

  • 가장 이상적이다. 자식이 부모로서 is-a 합당한가 ?
  • notebook is a computer (o)
  • laptop is a desktop (x)
  • computer 라는 공통 속성이 있고 (부모클래스) laptop, notebook 는 공통 속성을 각각 상속받는다.

오버라이딩과 오버로딩

  • 상속에서 쓰이는 개념
  • 같은 이름의 함수가 있으면 자식의 함수가 우선
  • (참고) 오버로딩
    • 같은 공간 (네임스페이스)안에 같은 이름의 함수를 정의하는 것을 함수 오버로딩이라고 한다.
    • 하지만 파이썬에서는 오버로딩을 인정하지 않는다. 마지막으로 정의된 함수만 인정 (c++ 함수 오버로딩 가능)

is-a 상속 예시

# 부모 : 자식이 모두 가지는 공통된 속성(attribute)을 모두 여기에서 정의
class Computer:
    def __init__(self, cpu, ram):
        self.cpu = cpu
        self.ram = ram

    def calculate(self):
        print('컴퓨터 계산중')

    def __str__(self):
        return '나는 컴퓨터입니다. '


# 부모클래스 computer를 상속받은 Notebook 클래스 정의
class Notebook(Computer):
    def __init__(self, cpu, ram, touch='normal', cam='small'):
        # 1. 클래스 이름으로 접근
        Computer.__init__(self, cpu, ram)
        self.touch = touch
        self.cam = cam

    def calculate(self): # 오버라이딩  - 같은 이름의 함수가 있으면 자식의 함수가 우선
        print('노트북 계산중')

    def __str__(self):
        return super(Notebook, self).__str__() + '그리고 난 노트북이죠!'

# 부모클래스 computer를 상속받은 Desktop 클래스 정의
class Desktop(Computer):
    def __init__(self, cpu, ram,  external_graphic = "Geforce"):
        # 2. super()로 접근
        super(Desktop, self).__init__(cpu, ram)
        # super(type, obj) -> bound super object; requires isinstance(obj, type)
        self.external_graphic = external_graphic

    def calculate(self): # 오버라이딩
        print('데스크탑 계산중')

    def __str__(self):
        return super().__str__() + '그리고 난 데스크탑이죠!'

상속 : has-a, 객체합성

  • A policeman has a gun이라는 상태를 이런식으로 쓸 수있지 않을까?
class Gun:
  ....

class Police(Gun):
  ...
  • 과거의 레거시 문법 (현재는 아무도 안쓴다)
  • 그럼 이런 개념을 has-a가 아니라 어떻게 표현할 수 있을까? 객체합성으로 하자!

객체합성 (composition)

  • has-a 라는 현실 상황을 객체합성이라는 기법을 사용하여 해결한다. (고급기법)
  • A Police has a Gun.
class Gun:
    def __init__(self, kind):
        self.kind = kind

    def bang(self):
        print('빵야빵야')

# 객체합성
class Police():
    def __init__(self, gun_kind=''):
        if gun_kind:
            self.gun = Gun(gun_kind) # Gun클래스의 인스턴스객체를 생성하여 Police의 인스턴스 멤버로 할당한다.)
        else:
            self.gun = None #gun이라는 인스턴스 멤버는 있지만 값은 없는 상태

    def get_gun(self, gun_kind):
        self.gun = Gun(gun_kind)

    def shoot(self):
        if self.gun:
            self.gun.bang()
        else:
            print('당신에게는 총이 없습니다.')
p1 = Police('리볼버')
print(p1.gun.kind) # 리볼버
p1.shoot() # 빵야빵야

p2 = Police()
p2.shoot() # 당신에게는 총이 없습니다.
p2.get_gun('기관총')
p2.shoot() # 빵야빵야

__name__ = '__main__' 의미

  • 테스트를 위해 넣은 코드가 모듈 import시에 실행되지 않도록 한다.
  • python test.py 처럼 직접 파일을 실행시키면 if 문이 참이되어 if 다음 문장들이 수행된다. (main file : 실행파일)
  • 참고
  • 모듈을 개발할 때 확인을 위한 테스트 코드 작성시에 활용한다.
if __name__ == "__main__":
  ....
  테스트 실행문

UML

  • uml
  • sw architect가 설계 할 때 사용
  • 한눈에 클래스의 상속 관계를 알 수 있는 도안

캡슐화

  • 클래스의 존재 목적 : 연관성 있는 정보의 묶음
  • 그럼 연관성의 기준을 어디까지 잡을 건지? (사람마다 다를 수 있다. 정답은 없다.)
  • 어디까지 캡슐로 묶을 건가? 이걸 잘 짜는게 (UML) sw architect의 역할

상속 실습

  • Person 이라는 부모 클래스를 갖는 Retailer 클래스와 Buyer 클래스를 작성한다.
  • 수업자료