Java

[Java] 절차 지향 프로그램 vs 객체 지향 프로그래밍

에띠 2022. 4. 12. 12:23
728x90

프로그래밍 언어에는 **절차지향 프로그래밍(Procedural Programming)**과 **객체지향 프로그래밍(Object-Oriented Programming, OOP)**이 있습니다. 절차지향 프로그래밍은 주로 순차적 처리를 중요시하고, 객체지향 프로그래밍은 실제 세계의 객체들을 모델링하여 프로그램을 구성하는 방법입니다. 이번 포스팅에서는 객체지향 프로그래밍의 주요 개념들을 소개하고, 자바를 사용하여 이를 구현하는 방법을 살펴보겠습니다.

 


1. 절차지향 프로그래밍 vs 객체지향 프로그래밍

절차지향 프로그래밍

절차지향 프로그래밍은 프로그램을 순차적으로 작성하는 방법입니다. 이는 물위가 흐르는 것처럼 위에서 아래로 차례대로 실행되는 방식으로, 주로 함수와 변수를 사용하여 프로그램을 작성합니다.

  • 장점: 이해하기 쉽고, 구현이 간단합니다.
  • 단점: 코드의 유지보수나 확장성에 한계가 있으며, 여러 명이 협업하기 어려운 점이 있습니다.

객체지향 프로그래밍

객체지향 프로그래밍은 실제 세계의 객체를 모델링하여 프로그래밍을 하는 방식입니다. 데이터를 객체로 묶고 객체의 행동을 메소드로 정의하는 방법입니다. 이는 데이터와 기능을 하나의 덩어리로 묶어서 처리합니다.

  • 장점: 여러 명이 협업하기 좋고, 코드의 재사용성과 유지보수성이 뛰어납니다.
  • 단점: 설계가 복잡하고, 초기 학습에 시간이 걸릴 수 있습니다.

2. 객체지향 프로그래밍의 주요 개념

클래스(Class)

클래스는 객체를 생성하기 위한 설계도 역할을 합니다. 클래스 내부에는 객체의 **상태(변수)**와 객체가 할 수 있는 **행동(메소드)**이 정의됩니다.

 

  • 클래스 예시:
 
  접근제어자 class 클래스명{
      자료형 필드1;
      자료형 필드2;
      ...
      메소드1() {
          ...
      }
      메소드2() {
          ...
      }
      ...
  }
public class User {
    String id;  // 아이디
    String name;  // 이름
    String pw;  // 비밀번호
    int age;  // 나이
    double point;  // 포인트

    // 유저 정보를 출력하는 메소드
    public void info() {
        System.out.println("아이디 : " + id);
        System.out.println("이름 : " + name);
        System.out.println("비밀번호 : " + pw);
        System.out.println("나이 : " + age);
        System.out.println("포인트 : " + point);
    }
}

객체(Object)

클래스를 기반으로 실제 메모리에 생성된 실체를 객체라고 합니다. 객체는 클래스를 통해 생성되며, 클래스에서 정의된 변수와 메소드를 통해 데이터를 처리합니다.

  • 객체 생성 예시:
 
클래스명 객체명 = new 생성자(클래스명)();
public class Oop1 {
    public static void main(String[] args) {
        // User 클래스를 기반으로 객체 생성
        User user = new User();
        user.id = "apple";
        user.name = "김사과";
        user.pw = "1234";
        user.age = 25;
        user.point = 280;

        user.info();  // 객체의 정보를 출력

        User member = new User();
        member.id = "banana";
        member.name = "반하나";
        member.pw = "1111";
        member.age = 26;
        member.point = 250;
        member.info();
    }
}

 

생성자(Constructor)

생성자는 객체가 생성될 때 호출되는 특별한 메소드입니다. 클래스와 동일한 이름을 가지며, 객체가 생성될 때 필드를 초기화하는 역할을 합니다. 생성자는 반환 타입이 없고 필드를 초기화하는데 사용됩니다.

  • 생성자 예시:
public class Member {
    private String userid;
    private String userpw;

    // 빈 생성자
    public Member() {
        System.out.println("Member 객체가 만들어졌어요");
    }

    // 사용자 정의 생성자
    public Member(String userid, String userpw) {
        this.userid = userid;
        this.userpw = userpw;
    }

    public void info() {
        System.out.println("아이디 : " + userid);
        System.out.println("비밀번호 : " + userpw);
    }
}

public class Oop2 {
    public static void main(String[] args) {
        // 빈 생성자 호출
        Member apple = new Member();
        apple.info();

        // 사용자 정의 생성자 호출
        Member banana = new Member("banana", "1234");
        banana.info();
    }
}
 

 

3. OOP의 주요 특징

oop : 객체지향 프로그래밍, Object Oriented Programming의 약자

은닉화(Encapsulation)

은닉화는 객체의 상태(변수)에 외부에서 접근하지 못하도록 private 접근 제어자를 사용하여 은닉하고, setter/getter 메소드를 통해 외부에서 값을 설정하거나 가져올 수 있도록 하는 방법입니다.

  • 은닉화 예시:
public class Member {
    private String userid;
    private String userpw;

    // setter 메소드
    public void setUserid(String userid) {
        this.userid = userid;
    }

    // getter 메소드
    public String getUserid() {
        return userid;
    }
}

 

추상화(Abstraction)

추상화는 공통의 속성이나 기능을 하나로 묶는 과정입니다. 이를 통해 세부적인 구현을 숨기고 핵심 기능만 제공하여 복잡성을 줄일 수 있습니다.

  • 추상화 예시:
// Student 클래스를 추상화하여 점수 관련 기능을 제공
public class Student {
    private int kor;
    private int math;

    public int getKor() {
        return kor;
    }

    public void setKor(int kor) {
        this.kor = kor;
    }

    public int getMath() {
        return math;
    }

    public void setMath(int math) {
        this.math = math;
    }

    public void showScore() {
        System.out.println("국어: " + kor + ", 수학: " + math);
    }
}

 

캡슐화(Capsulation)

캡슐화는 관련된 데이터메소드를 하나로 묶는 과정을 의미합니다. 객체가 맡은 역할을 수행하기 위해 데이터와 메소드가 하나로 묶여야 합니다.

 

✅ 은닉화
- 내부 데이터, 내부 연산을 외부에서 접근하지 못하도록 은닉 혹은 격리시키는 것
- 변수에 접근제한자를 private로 지정
- setter, getter 메소드를 사용하여 변수의 접근, 제어


✅ 추상화
- 공통의 속성이나 기능을 묶어 이름을 붙이는 것
- 클래스를 정의하는 것


✅ 캡슐화
- 실제로 구현되는 부분을 외부에 드러나지 않도록 캡슐로 감싸 이용방법만 알려주는 것
- 변수와 함수를 하나로 묶는 것
- 객체가 맡은 역할을 수행하기 위한 하나의 목적을 하나로 묶은 과정

 

생성자(Constructor)
- new 연산자를 통해 객체를 생성할 때 반드시 호출, 제일 먼저 실행되는 메서드
- 클래스명과 동일한 이름을 가진 메서드
- 필드를 초기화하는 역할
- 반환타입 없음
- 직접 생성하지 않으면 JVM이 자동으로 빈 생성자를 만들어 호출

[public] 클래스명() {
  생성자가 호출되면 실행할 문장;
  ...
}

 

 

4. 필드의 선언과 초기화

Java에서 객체를 생성할 때, 필드(변수)의 값을 설정하지 않으면 자동으로 기본값이 할당됩니다. 기본값은 각 데이터 타입에 따라 다릅니다.

자료형 기본값
byte 0
short 0
int 0
long 0L
char \u0000
float 0.0
double 0.0
boolean false
String, 배열, 객체(클래스), 인터페이스 null

 

즉, 객체를 생성했을 때 그 객체의 필드가 초기화되지 않으면, 위의 기본값으로 자동 초기화됩니다. 예를 들어, int 타입의 필드는 0으로, boolean 타입의 필드는 false로 초기화됩니다.


5. 생성자 메소드 오버로딩

생성자 오버로딩같은 이름의 생성자를 여러 개 정의하는 것입니다. 중요한 점은 파라미터의 갯수와 타입이 달라야 한다는 점입니다.

생성자 오버로딩을 사용하면, 같은 클래스에서 서로 다른 방식으로 객체를 생성할 수 있습니다. 예를 들어, Member 클래스에서 기본값을 설정할 수도 있고, 특정 값을 지정할 수도 있습니다.

예시: 생성자 오버로딩

public class Member {
    private String userid;
    private String userpw;

    // 기본 생성자
    public Member() {
        System.out.println("Member 객체가 만들어졌어요");
    }

    // 파라미터가 두 개인 생성자
    public Member(String userid, String userpw) {
        this.userid = userid;
        this.userpw = userpw;
    }

    // 파라미터가 더 많은 생성자
    public Member(String userid, String userpw, String name) {
        this.userid = userid;
        this.userpw = userpw;
        // 추가 필드 처리 가능
    }
}


this 키워드

this는 현재 객체 자신을 참조하는 키워드입니다. 주로 생성자나 메소드 안에서, 객체의 필드매개변수의 이름이 동일할 때, 이를 구분하기 위해 사용합니다.

예시: this 키워드 사용

public class Member {
    private String gender;

    // 매개변수와 필드 이름이 동일할 때 this를 사용하여 구분
    public void setGender(String gender) {
        this.gender = gender;  // this.gender는 필드, gender는 매개변수
    }
}

위 코드에서 this.gender는 객체의 필드 gender를 가리키고, gender는 메소드의 매개변수를 가리킵니다. 이렇게 this를 사용하면, 둘을 구분할 수 있습니다.

this() 키워드

this()는 현재 클래스의 다른 생성자를 호출할 때 사용됩니다. 같은 클래스 내에서 생성자끼리 서로 호출할 수 있도록 하는 방식입니다.

예시: this() 키워드 사용

public class Member {
    private String userid;
    private String userpw;
    private String name;

    // 기본 생성자
    public Member() {
        this("defaultUser", "defaultPass", "defaultName");
    }

    // 매개변수가 있는 생성자
    public Member(String userid, String userpw, String name) {
        this.userid = userid;
        this.userpw = userpw;
        this.name = name;
    }
}

위 코드에서 Member() 기본 생성자는 this("defaultUser", "defaultPass", "defaultName")를 호출하여 다른 생성자를 호출합니다. 즉, 기본 생성자를 사용하면 기본값을 갖는 Member 객체가 생성됩니다.

 

 

6. 객체 배열

객체 배열은 기본형 데이터의 배열처럼 객체를 여러 개 다루는 방식입니다. 객체 배열을 만들기 위해서는 다음과 같은 방식으로 선언하고 초기화할 수 있습니다.

객체 배열 선언 및 초기화

클래스명[] 참조변수 = new 클래스명[요소의 개수];

 

예를 들어, Member 클래스 객체를 3개 저장할 배열을 선언하려면:

Member[] members = new Member[3];  // Member 객체를 3개 담을 수 있는 배열 선언

 

그리고 각 배열 요소에 Member 객체를 생성하여 할당해줍니다:

members[0] = new Member();
members[1] = new Member();
members[2] = new Member();

배열을 사용할 때 중요한 점은 객체 배열을 선언하고 나면, 그 배열의 각 요소는 기본적으로 null로 초기화된다는 것입니다. 따라서 반드시 new 키워드를 사용하여 각 요소에 객체를 할당해줘야 합니다.

객체 배열 예시

public class Student {
    private int no;
    private String name;
    private int kor;
    private int math;
    private int eng;

    // 기본 생성자
    public Student() {
    }

    // 모든 필드를 초기화하는 생성자
    public Student(int no, String name, int kor, int math, int eng) {
        this.no = no;
        this.name = name;
        this.kor = kor;
        this.math = math;
        this.eng = eng;
    }

    // Getter, Setter, toString() 메소드 생략
}

public class Oop4 {
    public static void main(String[] args) {
        // 학생 객체 배열 생성 (3명)
        Student[] students = new Student[3]; 
        students[0] = new Student(1, "김사과", 90, 85, 88);
        students[1] = new Student(2, "반하나", 80, 75, 70);
        students[2] = new Student(3, "오렌지", 95, 90, 92);

        // 각 학생의 정보를 출력
        for (Student s : students) {
            System.out.println(s);
        }
    }
}

실행 결과:

 
학생번호=1, 이름=김사과, 국어점수=90, 수학점수=85, 영어점수=88
학생번호=2, 이름=반하나, 국어점수=80, 수학점수=75, 영어점수=70
학생번호=3, 이름=오렌지, 국어점수=95, 수학점수=90, 영어점수=92

 

728x90