다형성(Polymorphism) 그리고 추상화(Abstract)
Language/Python

다형성(Polymorphism) 그리고 추상화(Abstract)

뉴비뉴 2020. 7. 3.

다형성(Polymorphism)

다형성이란 유사한 형태를 갖고 있지만 완전히 다른 행동을 할 때 다형성이 적용되었다고 합니다.

간단하게 말하면 같은 모양의 코드가 다른 동작을 하는 것을 의미합니다.

다형성은 코드의 양을 줄이고, 여러 객체 타입을 하나의 타입으로 관리가 가능하여 유지보수에 용이합니다.

 

[뜬금]

signature란 메소드가 어떤 것인지 알 수 있습니다.

서명같은 것!

signature = Method name + Parameter list

 

다형성의 하위 개념인 Overriding 과 Overloading 에 대해 알아보겠습니다.

Method Overriding

- 부모 클래스 메소드와 자식 클래스의 메소드 signature 가 맞다면 자식은 부모의 메소드를 오버라이딩하여 사용하고 있는 것 입니다.

- 부모 클래스의 메소드를 무시하고, 자식 클래스에 새롭게 정의 된 메소드를 사용하게 됩니다.

Overriding 예시

class Parent:
    def name(self):
    	self.name = '이소룡'
        return self.name
        
        
 class Child(Parent):
    def name(self):
    	self.name = '손오공'
        return self.name
        

부모의 메소드를 상속받았지만 결과를 보면 자식에서 부모의 메소드를 오버라이딩하여 새로운 값이 출력되는 것을 확인할 수 있습니다.

 

Method Overloading

- 어떠한 클래스가 다양한 메소드를 가질 수 있습니다.

- 메소드 네임은 동일하지만 파라미터가 달라서 여러가지 다른 형태로 사용할 수 있다는 것이 오버로딩이라고 합니다.

def func(first, second, third=None):
    if third is None:
    	print("The value for third is None")
    else:
    	print("Third has a value")

func(1, 2)
>>> "The value for third is None"

func(1, 2, 3)
>>> "Third has a value

Overloading 예제

추상화(Abstract)

Abstract Data Types(ADT)

추상화

-  추상화 인터페이스에 의존하고, 구체적인 구현에는 의존하지 않는 것을 말하는 것

- 현실에 있는 것을 그대로 설명하면 이해하기 어려운 경우가 많습니다. 이럴 때 추상화라는 것을 사용하여 실제 데이터에 위반하지 않고, 추상화하여 사람이 보기좋게 만들 수 있는 것을 의미합니다. 

 

예를 들어보겠습니다.

복잡해보이는 지하철 노선도

위 사진을 보면 사람마다 다르겠지만 뭔가 우리가 보던 지하철노선도와는 많이 복잡해보입니다.

하지만 실제 지도를 토대로 만들었기 때문에 정확한 데이터입니다. 구체적인 구현에 의존한 것이라고 볼 수 있습니다.

보기좋은 지하철노선도

위 사진은 추상화가 되지않은 구체적인 구현에 의존한 지하철노선도보다는 구체적으로 제공하는 정보가 없지만

지하철을 이용하려는 사람이 보기에 좋은 구조를 갖고 있습니다.

 

추상화는 이렇 듯 생각의 단위를 묶어서 그룹으로 만들 수 있으며, 그것이 무엇을 의미하는지를 알 수 있도록 해줍니다.

 

추가로 추상화는 프로그래밍의 중요한 도구이기에 그것을 제대로 사용할 수 있는 개발자가 되어야 합니다.

결국 우리가 만드는 코드, 프로그램들은 쌓아올려진 지식의 토대 위에 숟가락을 하나 더 올리거나, 혹은 조금 더 추상화하는 것이기 때문입니다. 라이브러리를 쓰거나, 특정 언어로 코딩하는 것 자체가 사물에 대한 형상을 추상적인 언어로 기술하는 행동이기 때문입니다.

함수를 잘 만드는 것은 가장 기본적인 부품을 제대로 만드는 것이며, 추상화를 제대로 실천할 수 있는 대표적인 실천방법 입니다.

함수가 길어지고, 이해되는 코드보다 이해되지 않는 코드가 늘어나는 것도, 추상화 실패의 원인이 있습니다. 따라서 제대로 된 부품을 규격에 맞게 설계하고, 그것을 구현하는데 필요한 추상화 기술을 익히는 것이 그 해결책 입니다. 변경에 여유를 가지기 위해서는 구체적인 것에 의존해서는 안되며, 추상적인 인터페이스를 관리하는 것이 핵심입니다. -Reference 링크 블로그에서 발췌하였음-

 

추가로 추상화란 클래스인데 abstract method가 있는 것을 Abstract Class 라고 말합니다.

이거만 듣고 이해하기엔 좀 무리가 있습니다.

Abstract method 란 메소드가 정의가 되어있는데 이 메소드는 signature 부분만 정의가 되어있습니다.

signature 는 메소드를 식별할 수 있는 서명 정도라고 위에서 설명했습니다.

 

그렇다면 signature 만 있고, 동작하는 로직이 없는데 왜 필요할까요?

 

사람들이 여러명이 함께 작업한다고 가정해보겠습니다.

나는 Car 라는 클래스를 만들고, method signature를 만들어서 Car라는 클래스에 꼭 필요한 기능들을 명세하게 됩니다.

그럼 다른 개발자들은 method signature 를 참고하여 실제 돌아가는 구현부를 만들게 되는 것 입니다.

 

- Abstract Class 는 instance 를 만들 수 없기 때문에 실행시킬 수 없습니다.

 

일반적인 클래스(자식)에서 Abstract Class(부모) 를 상속하고, 오버라이드까지 해서 완전히 구현을 한 뒤,

일반적인 클래스(자식)에서 인스턴스를 만들어 활용할 수 있습니다.

 

import abc

class Room(object):
    __metaclass__=abc.ABCMeta
    
    @abc.abstractmethod
    def openDoor(self):
    	pass
        
    @abc.abstractmethod
    def openWindow(self):
    	pass
        
class BedRoom(Room):
    def openDoor(self):
        print("Open Door")
        
    def openWindow(self):
    	print("Open Window")
        

class Lobby(Room):
    def openDoor(self):
        print("Open Lobby)
        
room1 = BedRoom()
print(issubclass(BedRoom, Room), isinstance(room1, Room)
>>> ture, true

lobby1 = Lobby()
print(issubclass(Lobby, Room), isinstance(lobby1, Room)
>>> true, false

issubclass란 issubclass(class, classinfo)

ex) Lobby, Room -> Lobby 라는 클래스에 Room 이라는 클래스 정보가 있다면 True 아니면 False

isinstance 도 비슷한 맥락입니다.

 

Abstract 는 완전한 클래스의 상태가 아니라 signature 만 정의 된 상태라고 하였습니다.

하지만 그 정의 된 signature 안에 동작하는 로직을 넣어주면 완전한 인스턴스가 됩니다.

 

위 예시를 보면 금방 이해할 수 있습니다. room1 = BedRoom() 부분에서 BedRoom 구현부를 보면

class Room 에서 구조만 선언했던 openDoor, openWindow 를 오버라이딩하여 동작하게 하고,

isinstance 로 값을 확인해보니 True 라는 값이 출력됩니다.

 

반면에 Lobby 의 경우 openDoor 만 정의하였기 때문에 완전한 구현을 하지 못하였고, 그 말은 즉

인스턴스를 생성하지 못하였음을 의미합니다. 그래서 isinstance 에서 확인해보면 False 라는 값이 출력됩니다.

 

Object(Overriding Methods in objects)

object 라는 것은 기초의 오브젝트 클래스입니다.

모든 파이썬 클래스들은 object 의 Ddependency 를 갖고 있습니다.

ex) class Room: 으로 괄호가 없이 생성해도 object 를 갖고 있다고 생각하면 됩니다.

 

object has many hidden methods, 오브젝트는 몇 개의 기본 메소드를 갖고 있습니다.

- __init__ (constructor) 어떠한 인스턴스가 생성될 때 마다 필요한 것들을 추가/수정 하여 생성할 수 있습니다.

- __del__ (Destroy)

- __eq__ (Equalization) is 와 달리 메모리 스페이스를 건들지는 않고 값을 비교하게 됩니다.

class Room:
     numWidth = 100
     numHeight = 100
     numDepth = 100
     def __init__(self, parWidth, parHeight, parDepth):
         self.numDepth = parDepth
         self.numWidth = parWidth
         self.numHeight = parHeight
     def getVolume(self):
         return self.numDepth*self.numHeight*self.numWidth
     def __eq__(self, other):
         if isinstance(other, Room):
             if self.getVolume() == other.getVolume():
                 return True
             return False

- __cmp__ (비교)

- __add__ (덧셈)

 

정리

signature 이름이 동일하면 method overriding 이 가능하다.

super class 와 sub class 사이에 같은 이름의 signature 가 있다면 오버라이딩이 되어 자식클래스의 메소드가 대표하게 된다.

 

method signature 가 비슷하다면 이름은 동일하고 파라미터가 다른 경우엔 메소드 오버로드가 됩니다.

다양한 파라메타를 가질 수 있는 여러 메소드가 있고, 메소드 이름은 동일하다.

 

감사합니다.

 

Reference

- https://www.youtube.com/watch?v=1wpJEXjk8PE&list=PLbhbGI_ppZIQZIq1HiPM2rIBa_ikf9FWD&index=15

- https://cnpnote.tistory.com/entry/PYTHON-%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%93%9C-%EB%90%9C-%ED%95%A8%EC%88%98

- https://m.blog.naver.com/PostView.nhn?blogId=knix008&logNo=220700047637&proxyReferer=https:%2F%2Fwww.google.com%2F

댓글

💲 추천 글