객체지향 프로그래밍(Object Oriented Programming)
객체 지향을 지원하는 대부분의 언어들은 Class라는 문법을 제공한다.
상속 이라는 강력한 문법을 사용하여 코드 재사용성을 높이고, 유연한 설계와 확장성이 높다는 장점이 있다.
- 모든 것을 객체로 나누어 생각하고, 이 객체들을 활용하고 상호작용해서 일을 수행.
- 절차지향과는 다르게, 함수와 데이터를 함께 갖고 있음.
- 객체 내부의 데이터는 외부에 공개 할 필요가 없음. (캡슐화)
# FileReader
Class FileReader:
def __init__(self) -> None:
self.file_types = ["txt"]
self.file_history = []
def read(self, file_path: str) -> str:
self._validate(file_path)
...
def _validate(self, file_path: str) -> None:
for file_type in self.file_types:
if file_path.endwith(file_type):
return
raise ValueError("검증할 수 없는 확장자입니다.")
위에서 보는 코드와 같이 FileReader라는 객체 안에서 파일의 타입, 파일의 history와 같은 데이터 뿐만 아니라, read, validate와 같은 로직까지 하나의 객체 안에서 관리가 되고 있다.
함수는 적은 책임(한 개의 책임) 을 가지고 있는것이 좋다.
객체지향적인 코드에서는, 여러 객체로 이루어진다. (혹은 클래스)
각 객체(클래스)는 각각의 역할과 책임, 기능이 있으며, 전체적인 흐름은 객체와 함수간의 호출로 이루어진다.
위의 코드를 예시로 들자면, FileReader라는 객체(클래스)는 read라는 함수와 file_type이라는 자신만의 데이터를 가지고 있고, read 함수는 다시 _validate함수를 호출하여 확장자를 검증할것이다.
객체지향적인 프로그래밍은 위처럼 객체와 객체 사이에서도 함수 또는 메소드 호출로 코드 진행이 이루어지는데, 이 프로그래밍 방식은 앞서 말했듯 코드가 유연하고 확장성이 높다.
앞선 코드를 다음과 같이 확장할 수 있다.
# FileReader (added csv, xlsx reader)
Class FileReader(File):
def read(self, file_path: str) -> str:
self._validate(file_path)
data = self._open_file(file_path)
return self_.read(data)
@abstractmethod
def _read(self, data) -> str:
pass
@abstractmethod
def open_file(file_path: str) -> str:
...
def _validate(self, file_path: str) -> None:
for file_type in self.file_types:
if file_path.endwith(file_type):
class TxtFileReader(FileReader): #FileReader 클래스 상속.
def file_type(self) -> str:
return "txt"
def _read(self, data:str) -> str:
...
def somthingmethod(self, data:str) -> str:
return something
위처럼 FileReader 클래스를 상속받아서 TxtReader라는 파생 클래스를 생성했다. 이렇게 파생된 클래스들은 각자의 역할을 쉽게 바꾸도록 설계할 수 있다.
class Main:
def run(self) -> None:
processor = Processor(
file_reader = TxtFileReader(),
data_parser = DataParser(),
repository = Repository()
)
만일 Txt파일이 아니라 csv파일을 읽어야 한다면,
class Main:
def run(self) -> None:
processor = Processor(
file_reader = CsvFileReader(), # 이 라인만 변경해주면 된다.
data_parser = DataParser(),
repository = Repository()
)
이렇게 FileReader를 상속받은 클래스들이라면, 무리없이 코드가 작동할것이다.
이런 객체지향의 특성을 다형성 이라 한다.
객체지향적 프로그래밍은, 처음 코드를 보는 사람들은 보기 까다롭고 헷갈릴 수 있고 입력에 따라 다양한 work flow가 생성되기 때문에, 디버깅하기가 까다롭다. (물론 상대적인 기준)
하지만 여러 개발자가 협력을 해야하거나, 확장가능한 코드를 설계해야하는 경우에는 강력한 프로그래밍 방식이 될 것이다.