[edx] 캡슐화(Encapsulation)

Hyeon Soo·2022년 5월 9일
0

1. 개요

  • 객체를 사용할 때, 객체 내부의 변수 값은 외부에서 무제한으로 접근하고, 수정할 수 있게 될 경우, 객체를 이용하는 의미가 퇴색된다. 예를 들어, 온도의 단위를 수치 변경 없이 외부에서 변경하게 되면, 실제 온도가 바뀌는데 값에는 변화가 없어 의미가 달라진다. 이와 같은 경우를 방지하기 위한, 객체지향 프로그래밍의 원칙이자 객체의 특성이 캡슐화이다. 객체의 인스턴스 변수 값은 외부에서 직접 참조하거나 변경할 수 없어야하지만, 클래스 내부의 메서드들은 이에 접근할 수 있고 변경도 가능하며, 외부에서는 이러한 메서드들을 통해서만 값을 볼 수 있어야 한다.

2. public/private

  • Java 언어에서 메서드, 클래스, 클래스 내부 인스턴스 변수 등의 앞에 붙는 것들 중 하나로, 접근 제한자(Access modifier) 혹은 가시성 지정자(Visibility modifier)라고 부르는 듯 하다.

  • 인스턴스 변수이던 클래스이던 메서드이던, 수행하는 기능은 같다.

  • public 제한자의 경우, 외부에서 무제한 적인 접근과 사용이 가능하다.

  • private 제한자는 그렇지 않다. 인스턴스 변수나 메서드에 private 제한자를 사용할 경우, class member들 만이 접근이 가능하다.

3. static 변수와 메서드

  • Java에서 static은 변수, 메서드, 클래스 등에 사용할 수 있는데, 이 중 변수와 메서드에 사용하는 경우는 의미가 비슷하다. 또한, 접근과 사용과 관련하여 캡슐화와 연관이 있기도 하다.

  • 클래스 내부의 인스턴스 변수는 기본적으로 객체를 선언할 때마다 값을 부여받고 메모리에 각각 할당된다. 하지만, static 변수는 프로그램 실행시 즉시 부여했던 특정 값을 메모리에 할당하고, 모든 객체가 그 값을 공유한다. 그렇기 때문에, 모든 객체가 공유하는 특정한 값이 있는 경우, 그 값이 상수라면 상수로, 변수라면 변수로 생성하는 것을 통해 메모리를 아낄 수 있다. 예를 들어, 수의사 1명이 관리하는 동물원에 있는 동물들을 객체로 만든다고 가정하면, 동물별 담당 수의사는 상수로, 동물원 전체 동물의 수는 변수로 설정해야할 것이다. 이때, 둘 모두 static으로 설정하면, 일괄되게 관리할 수 있는 것이다.

  • 한편, 메서드의 경우, static 키워드를 사용하면 객체를 생성하지 않아도 클래스를 통해 메서드를 실행시킬 수 있다. 객체의 값이나 객체가 일정 역할을 수행하기 위해서 클래스 내부에 관련 메서드들을 작성할 필요가 있는데, 이를 util 혹은 helper 메서드라고 한다. 동물원의 예시를 다시 들면, 현재 동물원에 존재하는 모든 동물의 수를 알고 싶거나, 담당 수의사의 이름을 알고 싶다면, 동물의 수나 수의사의 이름을 반환하는 메서드를 작성할 것이다. 이때, static 메서드로 선언한다면, 개별 동물 객체를 거칠 필요 없이, 동물원 클래스를 통해 바로 원하는 값을 알 수 있다. 그렇기 때문에, static 메서드는 static 변수만을 참조해야 한다.

4. getter/setter

  • 대부분의 경우, 클래스 자체는 외부 접근이 가능하지만, 객체의 값은 직접 접근할 수 없도록 한다.

  • 하지만 객체의 인스턴스 값은 필요에 따라 이용할 수 있어야하고, 이를 도와주는 helper 메서드의 일종을 getter와 setter라 한다.

  • getter 메서드는 객체의 인스턴스 값을 반환한다. 이때, 인스턴스의 타입과 같은 타입을 반환해야 한다. 상술한 바와 같이, static 변수를 반환하는 경우, static 메서드로 선언해야한다. 중요한 점은, getter 메서드는 외부에서 읽을 필요가 있는 인스턴스에 대해서만 작성해야 한다. 외부에서 접근할 필요가 없는 인스턴스는 보안을 위해서라도 굳이 작성할 필요가 없다.

  • setter 메서드는 객체의 인스턴스 값을 수정한다. 그외의 사항은 getter와 큰 차이는 없다.

5. Constructor overloading

  • 객체를 생성할 경우, 클래스에 작성된 constructor에 따라 인스턴스 값을 설정하여 생성한다.

  • 그런데, 객체 생성시 많은 경우 디폴트로 선언할 수 있는 인스턴스가 있고, 일부의 경우만 값을 설정할 필요가 있는 클래스의 경우, 항상 모든 인스턴스를 입력해야만 객체 생성이 가능하다면 낭비가 크다.

  • 이러한 경우를 감안하여 생성의 유연성을 높이기 위한 방편이 constructor overloading이다. 예시는 다음과 같다.

public class Insect{
	private double weight;
    private double speed;
    
    public Insect(){
    	this(6.0, 100.0);
    }
    
    public Insect(double weightvalue){
        this(weightvalue, 100.0);
    }
    
    public Insect(double weightvalue, double speedvalue){
        weight = weightvalue;
        speed = speedvalue;
        //또는
        //this.weight = weightvalue;
        //this.speed = speedvalue;
        //이 경우, 우측의 parameter 변수의 이름이 weight, speed로 동일해도 된다.
    }
}
  • 이상의 코드는 3개의 생성자를 가지고 있지만, 각각 대응하는 parameter가 다르다. 첫번째 생성자는 parameter를 받지 않고, 두번째 생성자는 하나의 parameter만 받는다.

  • 이때, 첫번째와 두번째 생성자는 this()를 이용하고 있다. 이는 참조 연산자로, 동일한 이름을 가진 메서드나 변수를 참조하여 실행한다. Parameter를 하나도 입력하지 않은체 Insect객체를 생성하면, 첫번째 생성자를 사용하며, 첫번째 생성자는 동일한 이름을 가진 세번째 생성자에 6.0과 100.0을 parameter로 하여 실행한다. 즉, weight 6.0, speed 100.0을 인스턴스 값으로 가진 객체가 생성된다. 이를 chaining 이라 하는 듯 하다.

출처: https://learning.edx.org/course/course-v1:GTx+CS1331xII+2T2021/home

이상의 내용은 edx 플랫폼을 통해 GTx에서 제공하는 Introduction to Object-Oriented Programming with Java 강의의 내용을 개인적으로 정리한 것입니다. 그렇기 때문에, 부정확한 내용 혹은 잘못 이해하고 있는 내용이 있을 수 있으니 양해 부탁드립니다.

0개의 댓글