[CS] 1.2 프로그래밍 패러다임

angie·2022년 7월 31일
0

CS

목록 보기
1/8
post-thumbnail

** 본 포스팅은 '면접을 위한 CS 전공지식 노트'를 바탕으로 공부한 내용을 정리한 것입니다.

프로그래밍 패러다임

프로그래밍 패러다임이란?

: 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론

프로그래밍 패러다임의 분류

  1. 선언형
    • 함수형
  2. 명령형
    • 객체지향형
    • 절차지향형

선언형과 함수형 프로그래밍

  • 함수형 프로그래밍은 '순수 함수'들을 블록처럼 쌓아 로직을 구현하고 '고차 함수'를 통해 재사용성을 높인 프로그래밍 패러다임
  • 자바스크립트 : 함수가 일급 객체 -> 함수형 프로그래밍 방식이 선호됨

순수 함수

  • 출력이 입력에만 의존하는 것

고차 함수

  • 함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있는 것

일급 객체

: 고차 함수를 쓰기 위해 해당 언어가 일급 객체라는 특징(아래)을 가져야한다.

  • 변수나 메서드를 함수에 할당할 수 있다.

  • 함수 안에 함수를 매개변수로 담을 수 있다.

  • 함수가 함수를 반환할 수 있다.

객체지향 프로그래밍

  • 객체들의 집합으로 프로그램의 상호 작용을 표현
  • 데이터를 '객체'로 취급
  • 객체 내부에 선언된 메서드를 활용

특징

  1. 추상화 : 복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추려내는 것
  2. 캡슐화 : 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것
  3. 상속성 : 상위 클래스의 특성을 하위 클래스가 이어 받아서 재사용하거나 추가, 확장하는 것
    • 코드의 재사용, 계층적인 관계 생성, 유지보수성 측면에서 중요!
  4. 다형성 : 하나의 메서드나 클래스가 다양한 방법으로 동작하는 것 (ex. 오버로딩, 오버라이딩 )
오버로딩

: 같은 이름을 가진 메서드를 여러 개 두는 것 -> '정적 다형성'

  • 파이썬에서는 공식적으로 지원하지 않는다.
  • 프로그래밍에서의 오버로딩은, 동일한 이름의 함수를 매개변수에 따라 함수가 다르게 동작할 수 있게 하는 것
오버라이딩

: 주로 메서드 오버라이딩, 상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의하는 것 -> '동적 다형성'

  • 파이썬에서 오버라이딩은, 상위 클래스의 메서드를 하위 클래스에서 재정의하는 것 (덮어쓴다)

객체재향 설계 원칙

: SOLID 원칙

  • S : 단일책임원칙
  • O : 개방-폐쇄 원칙
  • L : 리스코프 치환 원칙
  • I : 인터페이스 분리 원칙
  • D : 의존역전 원칙

SRP : 단일 책임 원칙

(Single Responsibility Principle)

모든 클래스는 각각 하나의 책임만 가져야한다.

  • 하나의 클래스로 너무 많은 일을 하지 말라는 뜻!
  • 코드를 작성할 때, 단일 원칙 책임을 지키고 있는지 신경쓸 것
  • 너무 많은 기능을 수행하는 클래스는 GOD Object 라고 하기도 한다.
예시 (python)

아래와 같이 한 메소드가 두가지 기능을 동시에 한다면 작업을 분리해야한다.

class BookService:
  def findBookById(query):
    # DB에서 찾아오기
    # Log 파일에서 찾은 정보 쓰기

단일 책임 원칙에 맞게 아래와 같이 수정할 수 있다.

class BookService:
  def findBookById(query):
    # DB에서 찾아오기
    
  def wirteLog(log):
    # Log 파일에서 찾은 정보 쓰기

OCP : 개방-폐쇄 원칙

(Open Closed Principle)

유지 보수 사항이 생기다면 코드를 쉽게 확장할 수 있도록 하고, 수정할 때는 닫혀 있어야 한다.

= 기능 확장에는 열려있지만, 기능 수정에는 닫혀있어야 한다.

= 기존의 코드는 잘 변경하지 않으면서도, 확장은 쉽게 할 수 있어야 한다.

LSP : 리스코프 치환 원칙

(Liskov Substitution Principle)

프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 하는 것

  • 부모 객체에 자식 객체를 넣어도 시스템이 문제없이 돌아가게 만드는 것
  • = 부모 클래스의 인스턴스를 사용하는 위치에 자식 클래스의 인스턴스를 대신 사용했을 때 코드가 원래 의도대로 작동해야한다.
  • 자식 클래스가 부모 클래스의 행동 규약을 어기면 안된다는 것
  • = 자식 클래스가 부모 클래스의 변수와 메소드를 잘못 오버라이딩 하면 이런 문제가 발생한다.
예시 (python)
  1. 자식 클래스가 부모 클래스의 변수타입을 바꾸거나, 메소드의 파라미터 또는 리턴값이 타입 혹은 개수를 바꾸는 경우

    • 부모 클래스와 자식 클래스의 raise_pay 메서드는 파라미터 수가 다르다.
    • 부모 클래스와 자식 클래스의 wage 메서드는 리턴값이 다르다.
    class Employee:
      raise_percentage = 1.03
      
      def __init__(self, name, wage):
        self.name = name
        self.wage = wage
        
      def raise_pay(self):
        self._wage *= self.raise_percentage
        
      @property
      def wage(self):
        return self._wage
      
    class Cashier(Employee):
      
      def __init__(self, name, wage, number_sold=0):
        super().__init__(name, wage)
        self.number_sold = number_sold
        
      def raise_pay(self, raise_amount): # 파라미터 한개 더
        self.wate += self.raise_amount
        
      @property
      def wage(self):
        return "시급 정보를 알려줄 수 없습니다" # 리턴 값이 부모 클래스와 다르다.
  2. 자식 클래스가 부모 클래스의 의도와 다르게 메소드를 오버라이딩 하는 경우

    • sqaure 클래스의 width, height메서드는 부모 클래스와 다르게 작동한다.
    • 사실 정사각형은 직사각형의 행동 규약을 따르기 어렵기 때문에 애초에 상속을 안하는게 맞다.
    class Rectangle:
        """직사각형 클래스"""
    
        def __init__(self, width, height):
            """세로와 가로"""
            self.width = width
            self.height = height
    
        def area(self):
            """넓이 계산 메소드"""
            return self.width * self.height
    
        @property
        def width(self):
            """가로 변수 getter 메소드"""
            return self._width
    
        @width.setter
        def width(self, value):
            """가로 변수 setter 메소드"""
            self._width = value if value > 0 else 1
    
        @property
        def height(self):
            """세로 변수 getter 메소드"""
            return self._height
    
        @height.setter
        def height(self, value):
            """세로 변수 setter 메소드"""
            self._height = value if value > 0 else 1
    
    
    class Square(Rectangle):
        def __init__(self, side):
            super().__init__(side, side)
    
        @property
        def width(self):
            """가로 변수 getter 메소드"""
            return self._width
    
        @width.setter
        def width(self, value):
            """가로 변수 setter 메소드"""
            self._width = value if value > 0 else 1
            self._height = value if value > 0 else 1
    
        @property
        def height(self):
            """세로 변수 getter 메소드"""
            return self._height
    
        @height.setter
        def height(self, value):
            """세로 변수 setter 메소드"""
            self._width = value if value > 0 else 1
            self._height = value if value > 0 else 1

ISP : 인터페이스 분리 원칙

(Interface Segregation Principle)

하나의 일반적인 인터페이스보다 구체적인 여러 개의 인터페이스를 만들어야 한다.

인터페이스란?

** 파이썬엔 없는 개념!

: 추상 클래스 중에서 추상 메소드만 있고 일반 메소드는 없는 것

  • 클래스가 사용하지 않은 메소드인데, 상속을 통해 메소드를 물려받도록 하지말 것
  • 어떤 인터페이스(추상 클래스)를 상속받았을 때, 사용하지 않을 메서드가 있다면 인터페이스 분리 원칙 위반이다!!
  • 이를 방지하기 위해 인터페이스를 작게 분리해야한다. -> 더 작게 조갤 수 있을지 고민해야한다.

DIP : 의존 역전 원칙

(Dependency Inversion Principle)

추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 원칙

= 상위 계층은 하위 계층의 변화에 대한 구현으로부터 독립해야한다.

  • 상위 모듈에서 하위 모듈의 메소드를 사용하는데, 해당 메소드의 이름이 바뀌거나 하면 상위 모듈의 내용도 똑같이 바꿔야한다.

  • 상위 모듈과 하위 모듈 사이에 추상화 레이어를 만들어서 해결할 수 있다.

절차형 프로그래밍

  • 로직이 수행되어야 할 연속적인 계산 과정으로 이루어져 있다.
  • 계산이 많은 작업 등에 쓰임 ex) 대기 과학 관련 연산 작업, 머신 러닝의 배치 작업 등
profile
better than more

0개의 댓글