강의노트 09. [객체지향] oop (is-a, has-a, 객체합성)
09 Apr 2017 |패스트캠퍼스 컴퓨터공학 입문 수업을 듣고 중요한 내용을 정리했습니다. 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
객체지향 용어
- 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 클래스를 작성한다.
- 수업자료