객체 지향 프로그래밍 (Object Oriented Programming)
: 프로그램 구현에 필요한 객체를 파악하고 각각의 객체들의 역할이 무엇인지 정의하여 객체들 간의 상호작용을 통해 프로그램을 만드는 것
: 객체와 객체간의 연결로 구성되며 각각의 객체 안에 자료구조와 알고리즘이 들어있는 것
- 객체
: 클래스라는 틀에서 생겨난 실체 (instance)
객체지향과 절차지향의 차이
- 절차 지향 모델링
: 프로그램을 기능 중심으로 바라보는 방식
: 무엇을 어떤 절차로 할 것인가? 가 핵심
- 객체 지향 모델링
: 프로그램을 객체 중심으로 바라보는 방식
: 누가 어떤 일을 할 것인가? 가 핵심
: 객체를 도출하고 각각의 역할을 정의해 나가는 것에 초점
- 무엇이 더 나은가?
: 규모가 큰 프로그램의 경우 많은 기능을 수반하기 때문에 객체 지향이 적합
: 규모가 작은 프로그램의 경우 객체지향으로 설계하면 복잡해지기 때문에 절차 지향이 적합
객체 지향 프로그래밍의 특징
- 추상화 (abstraction)
: 객체들의 공통적인 기능 (기능, 속성)을 도출하는 것
: 객체 지향적 관점에서는 클래스를 정의하는 것을 추상화라고 할 수 있음
from abc import * #abc(abstract base class) 모듈의 클래스와 메소드를 갖고 온다.
#추상 클래스
class People(metaclass=ABCMeta):
#추상 메소드
@abstractmethod #추상메소드에는 abstractmethod를 선언해주어야 함.
def character(self):
pass
#상속받는 클래스
class Student(people):
def character(self, pow, think):
self.pow = pow
self.think = think
print('체력: {0}'.format(self.pow))
print('생각: {0}'.format(self.think))
#student object 생성
peo1 = Stuedent()
print('Student: ',peo1)
#student object 실행
peo1.character(30,10)
print(peo1)
- 캡슐화 (encapsulation)
: 실제로 구현되는 부분을 외부에 드러나지 않도록 하여 정보를 은닉하는 것
: 객체가 독립적으로 역할을 할 수 있도록 데이터와 기능을 하나로 묶어 관리하는 것
: 코드가 묶여있어 오류가 적어짐
: 데이터를 보지 않고 외부와 상호 작용할 때는 메소드를 이용하여 통신
: 보통 라이브러리로 만들어서 업그레이드해 사용
class Encap:
def __init__(self, value):
self.value = value
print('init: ',self.value)
def _set(self):
print('set: ',self.value)
def printTest(self):
print('printTest: ',self.value)
#def __printTest2(self):
# print('printTest: ',self.value)
# object 생성
e = Encap(10) ##init: 10
# object 실행_케이스1
e.__init__(20) ##init: 20
e._set() ##set: 20
e.printTest() ##printTest: 20
#e.printTest2() ##접근 불가
print('\n')
# 케이스2
e.__init__(30) ##init: 30
e._set() ##set: 30
e.printTest() ##printTest: 30
- 상속성 (inheritance)
: 하나의 클래스가 가진 특징(함수, 데이터)을 다른 클래스가 그대로 물려 받는 것
: 이미 작성된 클래스를 받아서 새로운 클래스를 만드는 것
: 기존 코드를 재활용하는 중요한 개념
- 다형성 (polymorphism)
: 약간 다른 방법으로 동작하는 함수를 동일한 이름으로 호출하는 것
: 동일한 명령의 해석을 연결된 객체에 의존하는 것
: 오버라이딩 (부모 클래스의 메소드와 같은 이름을 사용하며 매개변수도 같되 내부 소스를 재정의)
: 오버로딩 (같은 이름의 함수를 여러 개 정의한 후 매개변수를 다르게 하여 같은 이름을 경우에 따라 호출하여 사용)
class Person:
def run(self):
print("I'm a human: ", end='')
print('run')
def play(self):
print("I'm a human: ", end='')
print('play')
class Student(Person):
def run(self):
print("I'm a student: ", end='')
print('fast run')
def play(self):
print("I'm a student: ", end='')
print('play')
class teacher(Person):
def teach(self):
print("I'm a teacher: ", end='')
print('teach')
def play(self):
print("I'm a teacher: ", end='')
print('teach play')
# 리스트를 생성한다.
number = list()
# 생성한 리스트에 다형성 개념을 위해 다른 클래스(Student, teacher)가 상위 클래스(Person)를 참조할 수 있도록 한다.
number.append(Student()) # 리스트 끝에 서브 클래스 Student()를 넣습니다.
number.append(teacher()) # 다시 리스트 끝에 서브 클래스 teacher()를 넣습니다.
print("=========")
for Runner in number:
Runner.run() # 상위클래스인 Person의 run은 상속하여 사용하지만 내용은 다르다.
print("=========")
for Player in number:
Player.play() # 상위클래스인 Person의 play는 상속하여 사용하지만 내용은 다르다.
- 동적 바인딩 (Dynamic Binding)
: 가상 함수를 호출하는 코드를 컴파일 할 때, 바인딩을 실행 시간에 결정 하는 것
: 파생 클래스 객체에 대해 기본 클래스의 포인터로 가상 함수가 호출 될 때 일어남
: 함수를 호출하면 동적 바인딩을 통해 파생 클래스에 오버라이딩 된 함수가 실행됨
: 프로그래밍의 유연성을 높여주며 파생 클래스에서 재정의한 함수의 호출을 보장 (다형성)
객체 간의 관계
- 집합 관계
: 완성품과 부품의 관계
- 사용 관계
: 다른 객체의 필드를 읽고 변경하거나 메소드를 호출하는 관계
- 상속 관계
: 부모와 자식 관계
Reference
'Development > Development' 카테고리의 다른 글
추상 클래스와 인터페이스의 차이 (0) | 2023.03.10 |
---|---|
함수형 프로그래밍에 대해 알아보자 (0) | 2023.03.10 |
모든 주니어 개발자들에게 전하는 충고 5 (0) | 2023.02.06 |
프로젝트에 적용할 만한 기술 스택 (0) | 2023.02.06 |
도메인이 복잡한 소프트웨어를 개발할 때 (0) | 2023.02.06 |