프로그래밍 패러다임

hongxeob·2023년 2월 1일
0

CS

목록 보기
2/2
post-thumbnail

0. 프로그래밍 패러다임이란

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

  • 객체지향 프로그래밍
  • 함수형 프로그래밍
  • 절차형 프로그래밍
  • 등등..

크게 선언형,명령형으로 나누며, 선언형은 함수형이라는 하위 집합을 갖는다
또한 명령형은 다시 객체지향,절차지향으로 나눈다

1. 선언형 프로그래밍

  • 선언형 프로그래밍이란
    • 무엇을 풀어내는가에 집중하는 패러다임
    • 함수형 프로그래밍은 선언형 패러다임의 일종이다

특징

예시 코드

public class Calc {
    public int getMax(List<int> nums) {
        int result = 0;
        for (int num : nums) {
            result = Math.max(result, num);
        }
        return result;
    }
}

위 코드에서 getMax는 '숫자 리스트'만 받아서, 리스트 내의 정수 최댓값을 리턴한다
함수형 프로그래밍은 이와 같은 작은 ‘순수 함수’들을 블록처럼 쌓아 로직을 구현하고 ‘고차 함수’를 통해 재사용성을 높인 프로그래밍 패러다임이다

자바의 경우 jdk 1.8부터 함수형 프로그래밍 패러다임을 지원하기 위해 람다식, 생성자 레퍼런스, 메서드 레퍼런스를 도입했고 선언형 프로그래밍을 위해 스트림(stream) 같은 표준 API 등도 추가되었다.

  • 순수 함수
    • 출력이 입력에만 의존하는 함수를 의미한다. 위 코드에서 getMax()메소드가 순수 함수이다
  • 고차 함수
    • 함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있는 것을 말한다
    • 고차 함수를 쓰기 위해서는 해당 언어가 일급 객체라는 특징을 가져야 한다
  • 일급 객체
    • 변수나 메서드에 함수를 할당할 수 있다
      • 자바의 메소드는 변수에 할당할 순 없다
      • 반면 자바스크립트는 함수 표현식으로 자유롭게 대입이 가능하다
    • 함수 안에 함수를 매개변수로 담을 수 있다
      • 자바의 메소드를 메소드 입력값으로 보내는 행위는 불가능하다
      • 자바스크립트는 콜백 함수 형태로 자유롭게 전달이 가능하다
    • 함수가 함수를 반환할 수 있다
      • 자바의 메소드의 리턴값을 메소드 자체를 반환 행위는 불가능하다
      • 자바스크립트는 클로저(Closure) 기법을 통해 구성할 수 있다

참고 자료


2. 객체지향 프로그래밍

  • 객체지향 프로그래밍이란
    • 객체들의 집합으로 프로그램의 상호 작용을 표현한다(애플리케이션은 객체들의 집합으로 본다)
    • 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용하는 방식
    • 설계에 많은 시간이 소요되고, 처리 속도가 다른 프로그래밍 패러다임에 비해 상대적 느리다

핵심 개념

  • 추상화 (abstraction)
  • 캡슐화 (encapsulation)
  • 상속성 (inheritance)
  • 다형성 (polymorphism)

추상화

  • 복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추려내는 것을 의미한다
  • 특정 개념을 구체화 시키지 않고 모호화 하는 것
  • 여러가지 사물/개념에서 공통되는 특성을 묶어 이름을 붙이는 것
public interface Vehicle {
  public void time();
}
public class Car implements Vehicle {
    
    private String color;
    
    @Override
    public void time(){
        //얼마나 걸리는지 시간에 대한 메서드
    }
}
public class Ship implements Vehicle {
    
    private String color;
    
    @Override
    public void time(){
        //얼마나 걸리는지 시간에 대한 메서드
    }
}
  • 이동 수단으로 배를 이용할지, 자동차를 이용할지 못 정했지만, 이동 수단을 이용하기로 했으면 먼저 인터페이스(이동 수단)를 정의하고, 실제 구현체(배, 자동차)는 추후에 구현하면 된다
  • 구현체를 쉽게 교체할 수 있다는 장점이 있다

캡슐화

  • 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것
  • 일종의 리모콘과 같다. 필요한 기능은 버튼으로 외부에 노출되고,그 눈으로 보여질 필요가 없는 내용은 숨겨져 있다

상속화

  • 부모(상위) 클래스의 특성을 자식(하위) 클래스가 이어받아서 재사용하거나 추가, 확장하는 것을 말한다
  • 코드의 재사용 측면, 계층적인 관계 생성, 유지 보수성 측면에서 중요하다
public  class Vehicle{
    
    private String door;
    
    public void setDoor(String door){
        this.door=door;
    }
}
public class Car extends Vehicle{
    
    private String wheel;
    private String audio;
    //--getter...setter...
}
  • 위 코드에서 '모든 탈 것은 문이 있다'라고 가정하고, Vehicle에는 모든 탈것의 기본 사항만 포함
  • 그 외에 Car에게만 있는 내용은 바퀴와,음향장치 라고 가정한다
  • Car 클래스는 Vehicle 클래스에는 없는 변수와 메소드를 가진다
  • 그렇게 해도 Car 클래스는 Vehicledoor의 get,set 메소드를 사용할 수 있다

다형성

  • 하나의 메소드나 클래스가 다양한 방법으로 동작하는 것
  • 대표적으로 오버로딩 & 오버라이딩이 있다

오버로딩

  • 같은 이름의 메서드(함수)를 여러개 가지면서 매개변수 유형과 개수가 다르도록 하는 것
    • 한 클래스내에서 유사하지만 기능은 다르고, 이름이 같은 메소드를 여러개 정의하는 것
class Person {
    public void eat(String a) {
        System.out.println("I eat " + a);
    }
    public void eat(String a, String b) {
        System.out.println("I eat " + a + " and " + b);
    }
}
public class CalculateArea {
    public static void main(String[] args) {
        Person a = new Person();
        a.eat("apple");
        a.eat("tomato", "phodo");
    }
}
/*
I eat apple
I eat tomato and phodo
*/

매개변수의 개수에 따라 다른 함수가 호출되는 것을 알 수 있다

오버라이딩

  • 부모(상위) 클래스가 가지고 있는 메소드를 자식(하위) 클래스가 상속받아 재정의해서 사용
class Animal {
    
    public void bark() {
        System.out.println("멍멍");
    }
}
class Dog extends Animal {
    
    @Override
    public void bark() {
        System.out.println("왈왈");
    }
}
public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.bark();
    }
}
/*
왈왈
*/
  • 부모 클래스는 "멍멍"으로 짖게 해두었지만, 자식 클래스에서 "왈왈"로 짖게 바꾸었다
  • 자식 클래스 기반으로 부모의 메서드가 재정의됨을 알 수 있다

참고 자료


객체지향 설계 원칙 SOLID

객체지향 프로그래밍을 설계할 때는 SOLID 원칙. 즉 지켜야 하는 5가지 원칙이 있다

  • S : 단일 책임 원칙 (SRP; Single Responsibility Principle)
    • 모든 클래스는 반드시 단 하나의 책임만을 가져야 한다.
  • O : 개방 폐쇄 원칙 (OCP; Open-Closed Principle)
    • 모든 클래스는, 확장에는 열려 있고 수정에는 닫혀 있어야 한다.
    • 즉, 기존의 코드는 건드리지 않으며 신규 기능을 확장할 수 있어야 한다.
  • L : 리스코프 치환 원칙 (LSP; Liskov Substitution Principle)
    • 프로그램의 객체는, 프로그램의 정확성을 깨뜨리지 않으며 하위 타임의 인스턴스로 바꿀 수 있어야 한다.
    • 즉, 부모 객체 대신 자식 객체를 넣어도 기능이 동작해야 한다.
  • I : 인터페이스 분리 원칙 (ISP; Interface Segregation Principle)
    • 하나의 일반적인 (general) 인터페이스보다, 여러 개의 구체적인 (specific) 인터페이스를 만들어야 한다.
  • D : 의존 역전 원칙 (DIP; Dependency Inversion Principle)
    • "고차원 모듈은 저차원 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야 한다."
    • "추상화된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화된 것에 의존해야 한다."
    • "자주 변경되는 구체(Concrete) 클래스에 의존하지 마라"
    • "자신보다 변하기 쉬운 것에 의존하지 마라"
    • 로버트 C 마틴

관련 자료


3. 절차형 프로그래밍

  • 절차형 프로그래밍이란
    • 수행되어야 할 로직을 따라서 코드가 작성되는 패러다임

특징

  • 일이 진행되는 방식으로 그저 코드를 구현하기만 하면 되기 때문에 코드의 가독성이 좋고, 실행 속도도 빠르다
  • 모듈화하기가 어렵고 유지 보수성이 떨어진다는 점이 있다
profile
걍 하자 저스트 뚜잇

0개의 댓글