Lesson: Object-Oriented Programming Concepts

2024. 7. 1. 17:01High Level Programming Language/Learning the Java Language

[튜토리얼]

객체 지향 프로그래밍 언어를 처음 사용하는 경우, 코드를 작성하기 전에 몇 가지 기본 개념을 배워야 합니다. 이번 수업에서는 객체, 클래스, 상속, 인터페이스 및 패키지에 대해 소개합니다. 각 논의는 이러한 개념이 실제 세계와 어떻게 관련되는지에 중점을 두고, 동시에 자바 프로그래밍 언어의 문법을 소개합니다.

 

What is an Object?

객체는 객체 지향 기술을 이해하는 데 핵심입니다. 지금 주위를 둘러보면 실세계의 객체에 대한 많은 예시를 찾을 수 있습니다: 당신의 개, 당신의 책상, 당신의 텔레비전 세트, 당신의 자전거.

현실세계의 객체들은 두 가지 특징을 공유합니다: 모두 상태[state]와 행동[behavior]을 가지고 있습니다. 개는 상태(이름, 색깔, 품종, 배고픔)를 가지고 있으며 행동(짖기, 물건 가져오기, 꼬리 흔들기)을 합니다. 자전거 또한 상태(현재 기어, 현재 페달 회전수, 현재 속도)와 행동(기어 변경, 페달 회전수 변경, 브레이크 적용)을 가지고 있습니다. 현실세계 객체의 상태와 행동을 식별하는 것은 객체 지향 프로그래밍 관점에서 사고하기 시작하는 훌륭한 방법입니다.

지금 잠시 시간을 내어 당신의 주변에 있는 현실세계 객체들을 관찰해 보세요. 각 객체에 대해 "이 객체가 가질 수 있는 가능한 상태는 무엇인가?"와 "이 객체가 수행할 수 있는 가능한 행동은 무엇인가?"라는 두 가지 질문을 해보세요. 당신의 관찰을 기록하는 것을 잊지 마세요. 그렇게 하다 보면 현실세계 객체들이 복잡성이 다르다는 것을 알게 될 것입니다; 당신의 책상 램프는 두 가지 가능한 상태(켜짐[on]과 꺼짐[off])와 두 가지 가능한 행동(켜기[turn on], 끄기[turn off])만 가질 수 있지만, 당신의 책상 라디오는 추가적인 상태(켜짐, 꺼짐, 현재 볼륨, 현재 방송국)와 행동(켜기, 끄기, 볼륨 증가, 볼륨 감소, 탐색, 스캔, 조정)을 가질 수 있습니다. 또한 일부 객체는 다른 객체를 포함하고 있다는 것도 알게 될 것입니다. 이러한 현실세계 관찰은 모두 객체 지향 프로그래밍 세계로 변환됩니다.

A software object

 

소프트웨어 객체는 개념적으로 현실세계 객체와 유사합니다: 이들도 상태와 관련된 행동으로 구성됩니다. 객체는 상태를 필드(일부 프로그래밍 언어에서 변수)에 저장하고 메서드(일부 프로그래밍 언어에서 함수)를 통해 행동을 외부에 노출합니다. 메서드는 객체의 내부 상태에서 작동하며 객체 간의 주요 통신 메커니즘으로 작용합니다. 내부 상태를 숨기고 모든 상호작용을 객체의 메서드를 통해 수행하도록 요구하는 것을 데이터 캡슐화라고 하며, 이는 객체 지향 프로그래밍의 기본 원칙입니다.예를 들어, 자전거를 생각해 보겠습니다:

A bicycle modeled as a software object

 

현재 속도, 현재 페달 회전수 및 현재 기어와 같은 상태를 부여하고 해당 상태를 변경하는 메서드를 제공함으로써 객체는 외부 세계가 이를 사용할 수 있는 방식을 제어할 수 있습니다. 예를 들어, 자전거가 6단 기어만 가지고 있다면 기어를 변경하는 메서드는 1보다 작거나 6보다 큰 값을 거부할 수 있습니다.

코드를 개별 소프트웨어 객체에 묶는 것은 여러 가지 이점을 제공합니다. 이점에는 다음이 포함됩니다:

1. 모듈화: 객체의 소스 코드는 다른 객체의 소스 코드와 독립적으로 작성 및 유지 관리될 수 있습니다. 한 번 생성되면 객체는 시스템 내에서 쉽게 전달될 수 있습니다.
2. 정보 은닉: 객체의 메서드와만 상호 작용함으로써 내부 구현의 세부 사항이 외부 세계에 숨겨지게 됩니다.
3. 코드 재사용: 이미 존재하는 객체(아마도 다른 소프트웨어 개발자가 작성한 객체)를 프로그램에서 사용할 수 있습니다. 이를 통해 전문가들이 복잡하고 특정 작업에 특화된 객체를 구현하고, 테스트하고, 디버그할 수 있으며, 이를 신뢰하고 자신의 코드에서 실행할 수 있습니다.
4. 플러그 가능성과 디버깅 용이성: 특정 객체에 문제가 발생하면 해당 객체를 애플리케이션에서 제거하고 다른 객체로 대체할 수 있습니다. 이는 현실 세계에서 기계적 문제를 해결하는 것과 유사합니다. 볼트가 부러지면 기계 전체가 아닌 볼트만 교체합니다.

 

What Is a Class?

현실세계에서는 동일한 종류의 개별 객체를 많이 찾을 수 있습니다. 제조사와 모델이 모두 동일한 수천 대의 다른 자전거가 존재할 수 있습니다. 각 자전거는 동일한 설계도로 만들어졌기 때문에 동일한 구성 요소를 포함합니다. 객체 지향 용어로는, 당신의 자전거가 자전거로 알려진 객체들의 클래스의 인스턴스라고 합니다. 클래스는 개별 객체가 생성되는 설계도입니다.

다음의 Bicycle 클래스는 자전거의 가능한 구현 중 하나입니다:

public class Bicycle {

    private int cadence = 0; 
    private int speed = 0;
    private int gear = 1;

    // package-private
    public void changeCadence(int newValue) {
         cadence = newValue;
    }

    public void changeGear(int newValue) {
         gear = newValue;
    }

    public void speedUp(int increment) {
         speed = speed + increment;   
    }

    public void applyBrakes(int decrement) {
         speed = speed - decrement;
    }

    public void printStates() {
         System.out.println("cadence:" +
             cadence + " speed:" + 
             speed + " gear:" + gear);
    }
}

 

자바 프로그래밍 언어의 문법은 처음 접할 때 낯설게 보일 수 있지만, 자바 클래스의 설계는 이전에 논의한 자전거 객체에 기반하고 있습니다. 필드인 cadence, speed, gear는 객체의 상태를 나타내며, 메서드(changeCadence, changeGear, speedUp 등)는 외부 세계와의 상호작용을 정의합니다.

Bicycle 클래스에 main 메서드가 포함되지 않은 것을 눈치챘을 것입니다. 이는 자전거를 사용하는 애플리케이션의 설계도일 뿐, 완전한 애플리케이션이 아니기 때문입니다. 새로운 Bicycle 객체를 생성하고 사용하는 책임은 애플리케이션 내의 다른 클래스에 있습니다.

여기 두 개의 별도 Bicycle 객체를 생성하고 그들의 메서드를 호출하는 BicycleDemo 클래스가 있습니다:

class BicycleDemo {
    public static void main(String[] args) {

        // Create two different 
        // Bicycle objects
        Bicycle bike1 = new Bicycle();
        Bicycle bike2 = new Bicycle();

        // Invoke methods on 
        // those objects
        bike1.changeCadence(50);
        bike1.speedUp(10);
        bike1.changeGear(2);
        bike1.printStates();

        bike2.changeCadence(50);
        bike2.speedUp(10);
        bike2.changeGear(2);
        bike2.changeCadence(40);
        bike2.speedUp(10);
        bike2.changeGear(3);
        bike2.printStates();
    }
}

 

이 테스트의 출력은 두 자전거의 종료 페달 케이던스, 속도 및 기어를 인쇄합니다.

cadence:50 speed:10 gear:2
cadence:40 speed:20 gear:3

 

What Is Inheritance?

다양한 종류의 객체들은 종종 서로 공통된 부분을 가지고 있습니다. 예를 들어, 산악 자전거, 로드 자전거, 탠덤 자전거는 모두 자전거의 특성(현재 속도, 현재 페달 회전수, 현재 기어)을 공유합니다. 하지만 각각은 그들을 다르게 만드는 추가적인 특징들도 정의합니다: 탠덤 자전거는 두 개의 좌석과 두 개의 핸들바를 가지고 있으며, 로드 자전거는 드롭 핸들바를 가지고 있습니다. 일부 산악 자전거는 추가 체인 링을 가지고 있어 더 낮은 기어 비율을 제공합니다.

객체 지향 프로그래밍에서는 클래스가 다른 클래스에서 일반적으로 사용되는 상태와 행동을 상속받을 수 있습니다. 이 예제에서 Bicycle은 이제 MountainBike, RoadBike, TandemBike의 슈퍼클래스가 됩니다. 자바 프로그래밍 언어에서는 각 클래스가 하나의 직접적인 슈퍼클래스를 가질 수 있으며, 각 슈퍼클래스는 무제한의 서브클래스를 가질 수 있는 잠재력을 가지고 있습니다:
계층 구조에서 클래스들의 다이어그램.

A hierarchy of bicycle classes

 

서브클래스를 생성하는 문법은 간단합니다. 클래스 선언 시작 부분에서 상속할 클래스 이름 뒤에 extends 키워드를 사용합니다.

class MountainBike extends Bicycle {

    // new fields and methods defining 
    // a mountain bike would go here

}

 

이렇게 하면 MountainBike는 Bicycle과 동일한 필드와 메서드를 모두 가지게 되며, 이를 통해 고유한 기능에만 집중할 수 있습니다. 이로 인해 서브클래스의 코드는 읽기 쉽게 됩니다. 그러나 각 서브클래스의 소스 파일에 해당 코드가 나타나지 않기 때문에, 각 슈퍼클래스가 정의하는 상태와 행동을 올바르게 문서화하는 것이 중요합니다.

 

 

What Is an Interface

이미 배웠듯이 객체는 자신이 노출하는 메서드를 통해 외부 세계와의 상호 작용을 정의합니다. 메소드는 객체와 외부 세계의 인터페이스를 형성합니다. 예를 들어 TV 전면에 있는 버튼은 사용자와 플라스틱 케이스 반대편의 전기 배선 사이의 인터페이스입니다. "전원" 버튼을 누르면 TV를 켜고 끌 수 있습니다.

 

가장 일반적인 형태의 interface는 본문이 없는, (인터페이스 이름과)관련된 메서드들의 그룹입니다. 자전거의 행동을 interface로 지정하면 다음과 같이 나타날 수 있습니다:

interface Bicycle {

    //  wheel revolutions per minute
    void changeCadence(int newValue);

    void changeGear(int newValue);

    void speedUp(int increment);

    void applyBrakes(int decrement);
}

 

이 Bycycle interface를 구현하려면, 클래스의 이름을 (예를 들어 특정 자전거 브랜드인 ACMEBicycle로) 변경하고, 클래스 선언에서 implements 키워드를 사용합니다:

class ACMEBicycle implements Bicycle {

    int cadence = 0;
    int speed = 0;
    int gear = 1;

   // The compiler will now require that methods
   // changeCadence, changeGear, speedUp, and applyBrakes
   // all be implemented. Compilation will fail if those
   // methods are missing from this class.

    void changeCadence(int newValue) {
         cadence = newValue;
    }

    void changeGear(int newValue) {
         gear = newValue;
    }

    void speedUp(int increment) {
         speed = speed + increment;   
    }

    void applyBrakes(int decrement) {
         speed = speed - decrement;
    }

    void printStates() {
         System.out.println("cadence:" +
             cadence + " speed:" + 
             speed + " gear:" + gear);
    }
}

 

interface를 구현하면 클래스가 제공하기로 약속한 동작에 대해 보다 공식적으로 정의할 수 있습니다. 인터페이스는 클래스와 외부 세계 간의 계약[contract]을 형성하며, 이 계약은 컴파일러에 의해 빌드 시점에 강제됩니다. 클래스가 인터페이스를 구현한다고 주장하면, 그 인터페이스에 정의된 모든 메서드는 클래스가 성공적으로 컴파일되기 전에 소스 코드에 나타나야 합니다.

참고: ACMEBicycle 클래스를 실제로 컴파일하려면 구현된 인터페이스 메서드의 시작 부분에 public 키워드를 추가해야 합니다. 이에 대한 이유는 클래스와 객체, 인터페이스와 상속에 관한 수업에서 나중에 배우게 될 것입니다.

간혹, interface를 contract로 일컫는 개발자들이 있습니다.

 

What Is a Package?

패키지는 관련 클래스 및 인터페이스 집합을 구성하는 네임스페이스입니다. 개념적으로 패키지는 컴퓨터의 다른 폴더와 유사하다고 생각할 수 있습니다. 한 폴더에는 HTML 페이지를, 다른 폴더에는 이미지를, 또 다른 폴더에는 스크립트나 응용 프로그램을 보관할 수 있습니다. Java 프로그래밍 언어로 작성된 소프트웨어는 수백 또는 수천 개의 개별 클래스로 구성될 수 있으므로 관련 클래스와 인터페이스를 패키지에 배치하여 구성을 유지하는 것이 합리적입니다.

Java 플랫폼은 자신의 애플리케이션에 사용하기에 적합한 거대한 클래스 라이브러리(패키지 세트)를 제공합니다. 이 라이브러리는 "응용 프로그래밍 인터페이스" 또는 줄여서 "API"로 알려져 있습니다. 해당 패키지는 범용 프로그래밍과 가장 일반적으로 관련된 작업을 나타냅니다. 예를 들어, String 객체에는 문자열에 대한 상태와 동작이 포함되어 있습니다. File 객체를 사용하면 프로그래머는 파일 시스템에서 파일을 쉽게 생성, 삭제, 검사, 비교 또는 수정할 수 있습니다. Socket 객체를 사용하면 네트워크 소켓을 생성하고 사용할 수 있습니다. 다양한 GUI 객체는 버튼과 체크박스, 그리고 그래픽 사용자 인터페이스와 관련된 모든 것을 제어합니다. 말 그대로 수천 개의 수업 중에서 선택할 수 있습니다. 이를 통해 프로그래머는 특정 애플리케이션을 작동시키는 데 필요한 인프라가 아닌 특정 애플리케이션의 설계에 집중할 수 있습니다.

Java 플랫폼 API 사양에는 Java SE 플랫폼에서 제공하는 모든 패키지, 인터페이스, 클래스, 필드 및 메서드에 대한 전체 목록이 포함되어 있습니다. 브라우저에 페이지를 로드하고 북마크에 추가하세요. 프로그래머로서 이 문서는 가장 중요한 참조 문서가 될 것입니다.