객체지향프로그래밍 개요(예제코드 점검 필요,)

yuns_u·2021년 11월 20일
0

OOP(Object Oriented Programming)

객체지향프로그래밍이란 프로그램 설계방법론이자 개념의 일종이다.
프로그램을 데이터와 처리방법으로 나누는 것이 아니라 프로그램을 수많은 객체(object)라는 기본 단위로 나누고 이 객체들의 상호작용으로 서술하는 방식이다.

객체란 하나의 역할을 수행하는 method와 변수(데이터), 클래스, 인스턴스, 함수 등을 의미한다.

OOP의 기본전제는 기능(함수,변수)재사용이 가능하도록 설계 및 프로그래밍을 한다는 것이다.
최소 비용으로 최대 효율을 얻기 위해 개발된 개념이라고 할 수 있다.

OOP의 기본 개념은 설계(사람이 이해하는 방식)와 구현할 소스코드(컴퓨터가 이해하는 방식)간의 상호이해가 중요하다는 것이다. 하드웨어와 소프트웨어의 성능의 증가로 CPU 성능이 증가하고 소프트웨어 다중 실행이 가능해지면서 OOP의 모든 기능을 활용할 필요는 없어졌다.

OOP의 단점:

  • OOP의 개념을 무분별하게 사용하다보면 유지보수가 어려워질 수도 있기 때문에 설계방향 및 서비스 기능에 따라 사용해야한다.
  • OOP는 하나의 패러다임일 뿐이기 때문에 기존의 프로그래밍 패러다임(procedure programming, functional programming 등)들과 우열을 가릴 필요는 없다.
  • OOP는 주관성이 높아 소프트웨어 서비스 설계방향에 영향을 많이 받으므로 보편적으로 활용되는 개념에 대해 배운다.
  • OOP를 잘 구현하기 위해서는 프로그래밍뿐만 아니라 다양한 도메인에서 재사용 가능한 클래스, 메소드(기능) 설계가 필요하다.

OOP이전의 프로그래밍

  • OOP 개념이 나오기 전에는 배열과 함수, 변수를 많이 생성하고 활용하여 최대한 많은 기능을 적은 양의 소스코드파일에 넣었다.

  • 속성과 기능이 증가할 때마다 배열과 함수를 계속 생성해야했기 때문에 소스코드의 관리가 비효율적이었다.

  • 이에 따라 속성과 기능을 객체(object)라는 최소단위로 분리하는 OOP의 개념이 나오기 시작했다.

  • 프로그래밍에서 OOP의 개념을 항상 활용하는 것은 아니다. 데이터분석을 진행하는 경우, 모듈과 라이브러리를 활용한 분석 인사이트가 중요하다.

OOP의 필요성

Data-driven(데이터기반 의사결정), 컴퓨터하드웨어성능, 데이터양 증가에 따라 OOP활용도 증가하였다.

  • 프로그램 패러다임: OOP와 Procedural Programming, functioinal programming
  • 함수형은 함수의 사용을 극대화시켜서 코드의 가독성을 높여주는 형태이다. 프로그래밍 코드를 특정 상황에 특정 함수를 사용하기 위해 고안된 방법이다.
  • 특정 컴퓨터환경과 특정 대용량 개발환경에서 많이 쓰이고 있지만 절대적으로 좋은 프로그래밍은 아니다.

OOP와 일상생활

  • 일상생활에서 볼 수 있는 것, 실제로 머릿속에서 떠올릴 수 있는 것을 프로그래밍하는 것이 OOP의 중요한 점이다.
  • 절차 프로그래밍과 객체지향프로그래밍을 비교해보면 아래와 같다.
# 절차 프로그래밍(procedure programming, 일명 pp)
# 조건 또는 기능이 증가할 때마다 함수와 변수 같은 요소가 계속 증가할 수 있으므로 비효율적이다.

#케이스 1: 함수 활용
def carAttribute():
    speed = 50
    color = 'black'
    model = 'CarModel'
    return speed, color, model

#return 값을 통해 함수 요소값을 확인할 수 있다.
print('Car Attribute:', carAttribute())


#케이스 2: 변수 활용
speed =50
color ='black'
model = 'CarModel'
#해당 변수를 각각 명시해주어 확인할 수 있다.
print('Car Attribute: ', speed,color,model)


#객체지향프로그래밍(Object oriented Programming, OOP)
#절차 프로그래밍과 다르게 기능별로 수행되기 때문에 클래스 선언 순서와 관계없이 실행된다.

class Bus:
    def __init__(self, speed, color):
        self.speed = speed
        self.color = color
        
    def drive_bus(self):
        self.speed = 70
        
class Car:
    def __init__(self, speed, color, model):
        self.speed = speed
        self.color = color
        self.model = model
        
    def drive(self):
        self.speed = 50
        
myCar = Car(0, 'green', 'benz')
print('-------Car Object Result---------')
print('car speed: ',myCar.speed)
print('car color: ',myCar.color)
print('car model: ',myCar.model)
print('bus color: ',myBus.color)

myBus = Bus(0,'black')
print('-------Bus Object Result---------')
print('bus color: ',myBus.color)

#운전 중이 아니므로 speed는 0을 출력한다.
print('---speeds1---')
print('Car speed: ', myCar.speed)
print('Bus speed: ', myBus.speed)

#call object 'Car','Bus' method 
myCar.drive()
myBus.drive()

#운전 중이 아니므로 speed는 0을 출력한다.
print('---speeds2---')
print('Car speed by drive: ', myCar.speed)
print('Bus speed by drive: ', myBus.speed)

OOP의 구성

캡슐화

일반적인 정의: 객체의 속성과 행위(기능)을 하나로 묶고 실제 구현 내용의 일부를 은닉하는 것.
기본 개념: 내부 속성(변수)과 함수를 하나로 묶어서 클래스로 선언하는 일반적인 개념

  • 캡술화의 형태로 코드를 작성하지 않으면 특정 기능(함수, 변수)에 직접 접근해야한다.
  • 기능이 많아질수록 재사용의 개념을 활용하기 어려워진다.
  • _function(x) : 다른 곳에 import 할 수는 없지만 class 내의 함수로서는 부를 수 있다.
  • __function(x) : _ClassName__method로 Mangling된다. ClassName.__method로 접근이 불가하다.
    • Mangling : 변수/함수명을 그대로 사용하지 않고 일정한 규칙에 의해 변형시키는 것
#캡슐화 코드

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 & Composition)

상속(Inheritance)

상위 클래스의 모든 기능(함수, 변수)을 재사용할 수 있다.

#상속 코드

#클래스 선언
class Person:
    def __init__(self, name):
        self.name=name
        
class Student(Person):
    def study(self):
        print(self.name + ' studies hard.') #Person 클래스 상속받음(name 변수를 파라미터로 재사용)

class Employee(Person):
    def work(self):
        print(self.name + ' works hard.') #Person 클래스 상속받음(name 변수를 파라미터로 재사용)
        
#object 생성
s = Student('Dave')
e = Employee('David')

#object 실행
s.study() #Dave studies hard.
e.work() #David works hard.

포함(Composition)

다른 클래스의 일부 기능(함수)만을 재사용한다.

'개는 몸을 가지고 있다.'라는 관계로 설명된다.

# 포함코드

#클래스 선언
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def printPerson(self):
        print('Persom_printPerson')
        
class Student(Person):
    def __init__(self, name, age, id):
        Person.__init__(self, name, age)
        Person.printPerson(self)
        self.id = id
        
    def test(self, score):
        if score > 80:
            print(self.name+' studied hard.')
        
        else:
            print(self.name+' needs supplementary lessons.')
            
#object 생성
#한 번 생성된 object는 파라미터가 변하지 않는 이상 출력값 또한 변하지 않는다.
s = Student('Dave', 20, 1)

#object 실행
print('student's name: ', s.name) ## student's name: Dave
print('student's age: ', s.age) ## student's age: 20
print('student's id: ', s.id) ## student's id: 1

print('\n')

#object 한 개 더 생성하기
s2 = Student('Jamie', 25, 2)

#object 실행
print('student's name: ', s2.name) ## student's name: Jamie
print('student's age: ', s2.age) ## student's age: 25
print('student's id: ', s2.id) ## student's id: 2

#점수 입력
print('---test score result---')
s.test(50) ##Dave needs supplementary lessons.
s2.test(90) ##Jamie studied hard.

class Bill():
    def __init__(self, description):
        self.description = description
        
class Tail():
    def __init__(self, length):
        self.length = length
        
class Duck():
    def __init__(self, bill, tail):
        self.bill = bill
        self.tail = tail
        
    def about(self):
        print(f'This duck has a {self.bill.description} and a {self.tail.length}.')
        
#object 생성
duck = Duck(bill('bill object'), Tail('tail object'))

#object 실행
duck.about()

추상화

추상화(abstraction)은 복잡한 내용에서 핵심적인 개념 및 기능을 요약하는 것을 말한다.

  • object 기능에 따라 추상 클래스(상위 클래스)를 상속받아 개별적으로 클래스(하위클래스)를 생성한다.
  • 기본적으로 추상메소드를 선언하며 실제 실행되는 기능은 보여지지 않는다.
  • 실제 실행되는 기능은 선언된 추상클래스를 상속받은 다른 클래스의 메소드에서 확인할 수 있다.
  • 추상클래스를 사용하는 이유 : 대형 프로젝트를 진행하는 경우 또는 프로그램이 복잡해지는 경우 1차적인 설계를 위해 기능을 추상화시켜놓고 활용여부는 차후 결정하기 위함이다.

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)

다형성

다형성은 구현되는 하위클래스에 따라 클래스를 다르게 처리하는 기능이다.

  • 상속과 유사하다고 느껴질 수 있지만, 상속은 상위클래스의 기능(함수, 변수)을 재사용한다.
  • 아래의 그림과 같이 다형성은 상위클래스의 기능을 변경하여 사용하는 것이다.(그대로 재사용하지 않는다.)

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는 상속하여 사용하지만 내용은 다르다.

결과

=========
I'm a student: fast run
I'm a human: run
=========
I'm a student: play
I'm a teacher: teach play

추가공부

  • 헷갈리지 않도록 코드를 작성하자. 연산자를 효율적으로 활용하자.

  • 연산자 1개(is not) : A는 B가 아니다.

  • 연산자 2개(not, is): A가 아닌 것은 None이다.

# 오해하지 않도록 코드를 작성하자.
# foo: 프로그래밍 상에서 임시로 변수이름을 지정해줘야 할 때 주로 쓰이는 변수 이름이다.
foo = ''

# 가독성 좋음
if foo is not None: # 한 번만 해석하면 된다. (A는 B가 아니다.)
  print('가독성 좋음')

# 가독성 좋지 않음
if not foo is None: # 두 번 해석해야된다. (A가 아닌 것은 None이다.)
  print('가독성 좋지 않음')
profile
💛 공부 블로그 💛

0개의 댓글