40일차 (1) - java (스트링리스트, 접근 제한자, 정보 은닉과 캡슐화)

Yohan·2024년 4월 17일
0

코딩기록

목록 보기
55/156
post-custom-banner

스트링리스트

  • 스트링 배열을 관리하는 객체의 설계도
  • 다루는 필드에 배열이 2개 이상이 될 경우 스트링리스트로 묶어주면 기능들을 같이 쓰게 만들 수 있음
  • 임의의 스트링 배열을 필드로 등록해놓으면 스트링리스트 클래스를 참조해서 객체를 생성할 때 마다 각기 다른 배열을 계속 생성 가능
// 스트링 배열을 필드로 등록
    String[] sArr;

// 생성자를 통해 스트링 배열을 초기화
    StringList() {
        sArr = new String[0]; // 빈 배열
    }

// StringList 객체를 생성해서 사용가능
	StringList foods = new StringList();
	StringList userNames = new StringList();
    ...

접근 제한자 (access modifier)

클래스, 필드, 메서드, 생성자에 대한 접근 권한을 제한하는 키워드

  • 지역변수에는 접근 제한자를 붙일 수 없음

접근 제한자 종류

public

  • 어떤 클래스에서든 접근 가능한 최대한의 범위, 다른 패키지에서도 접근이 가능
    -> 즉, 접근 제한 자체가 없는 경우라고 보면됨

protected

  • 같은 패키지에서는 public과 같이 모든 클래스에서 접근 가능.
  • 다른 패키지에서는 상속받은 자식 클래스에서만 접근 가능.
  • default와 접근 제한 범위가 비슷하지만, 상속 여부에 따라 다름.

default (아무런 접근 제한자를 사용하지 않음)

  • 같은 패키지에서 접근 가능
  • 다른 패키지에서 접근 불가능

private

  • 같은 클래스에서 접근 가능
  • 다른 클래스에서 접근 불가능
  • 가장 폐쇄적인 제한자

접근 제한자를 사용하는 이유

  • 접근 제한자를 사용하여 클래스, 변수, 메서드, 생성자 등의 멤버에 대한 접근 범위를 제한함으로써 코드의 안정성을 높일 수 있다.
  • 사용자가 알 필요 없는 또는 알아서는 안되는 정보들은 숨겨줘야 한다.
    -> 이처럼 굳이 알 필요없이 정해진 대로만 사용하면 되기 때문에 사용자의 편의성은 올라간다는 장점이 있다.

정보 은닉과 캡슐화 (Encapsulation)

정보은닉(Infomation hiding)이란?

정보 은닉이란 객체의 상태를 숨기고 외부에서 접근할 수 없도록 보호하는 것

  • 정보 은닉을 사용하지 않으면, 객체의 필드에 불필요한 값이나 문제가 발생할 수 있는 값들이 직접 들어오는 것을 막을 수 없다.
  • 그렇기 때문에 앞에서 배운 접근 제한자를 적절하게 이용하여 직접적인 접근을 막고 메서드를 통해 접근하게 하는 것이 은닉

정보은닉을 해야하는 이유

  • 아무것도 모르는 사용자가 코드를 수정하고 삭제하고 등의 문제가 발생할 수 있기 때문이다.
package encap;

public class Car {

    String model; // 모델명
    int speed; // 현재 속도
    char mode; // 변속 모드 (D, N, R, P)
    boolean start; // 시동 온오프 상태

    public Car(String model) {
        this.model = model;
        this.mode = 'P';
    }
}
Car tesla = new Car("테슬라 모델 3");
tesla.speed = 1000000000;
tesla.speed = -124398523;
  • 테슬라의 속도가 10억km가 되어 화성까지 날아갈 위험에 처했다. 이런 말도 안되는 속도를 입력하는 것을 막을 방법이 없다. 또한 음수 값으로 들어오는 코드도 잘못된 코드일 것이다.
  • 심지어 객체가 생성 될 때의 변속 모드는 P 이다. 파킹 모드에서 속도를 올리는 것 또한 비정상적으로 객체가 움직이는 행위이다. 이러한 것을 막기 위해 정보 은닉을 사용할 것이다.

정보은닉 구현순서

  1. 필드에 접근제한자 private을 붙여서 외부로부터의 접근을 막음
  2. private을 붙이면 잘못된 접근을 막을 수 있지만 제대로 된 값의 접근 또한 막기 때문에 메서드를 통해서 초기화를 허용한다.
    이 때, 값을 받는 메서드가 setter 메서드, 값을 가져오기위한 메서드가 getter 메서드이다.
  3. setter와 getter 메서드는 접근 제한을 public으로 지정하여 어디서든 접근이 가능하게 한다.
  4. setter 메서드는 파라미터를 받아 유효성 검사를 진행한 후에 적절한 값들만 초기화 시키고 잘못된 값은 거른다.
  5. getter 메서드는 숨겨진 필드값을 리턴하는 행위를 담당한다.
public class Car {

    private String model; // 모델명
    private int speed; // 현재 속도
    private char mode; // 변속 모드 (D, N, R, P)
    private boolean start; // 시동 온오프 상태

    public Car(String model) {
        this.model = model;
        this.mode = 'P';
    }
		
		// setter: 필드값 변경을 대리하는 메서드
    public void setSpeed(int speed) {
        if(!start) {
					System.out.println("시동이 꺼져 있습니다.");
					return;
				}
				if(mode != 'D' || mode != 'R') {
					System.out.println("변속기 모드가 올바르지 않습니다.");
					return;
				}
				if (speed < 0 || speed > 200) {
						System.out.println("속도가 올바르지 않습니다.");
            return;
        }
        this.speed = speed;
    }

		// getter: 은닉된 필드값을 참조하는 메서드
    public int getSpeed() {
        return this.speed;
    }
}
  • 모든 필드를 private로 지정해서 외부의 접근을 막고, setSpeed()를 통해서만 speed를 초기화 할 수 있도록 세팅
    -> 이 과정이 정보은닉!
  • speed 변수를 보호해서 잘못된 값이 들어왔을 때 객체가 동작하지 못하는 상황을 방지

정보은닉 정리

  • 모든 필드를 private하고 getter, setter를 통해서만 값을 설정하고 가져옴

캡슐화(encapsulation)란?

객체의 상태와 동작을 하나의 단위로 묶어서 구현하는 것

  • 즉, 하나의 목적을 이루기 위해 관련있는 모든 것들을 하나의 캡슐에 담아 두는 것
// 시동 거는 기능
public void engineStart() {
    System.out.println("시동 버튼을 눌렀습니다.");
    System.out.println("시동이 걸렸습니다.");
}


// 엔진에 연료가 주입되는 기능
private void injectGasoline() {
    System.out.println("연료가 엔진에 주입됩니다.");
}
// 엔진오일이 주입되는 기능
private void injectOil() {
    System.out.println("엔진 오일이 순환합니다.");
}
// 실린더가 움직이는 기능
private void moveCylinder() {
    if (start) {
        System.out.println("실린더가 움직입니다.");
    } else {
        System.out.println("차가 고장났습니다.");
    }
}
  • 위 처럼 각자의 기능으로 구현되어있다면 하나로 연결시키기 힘들다.
// 시동 거는 기능
public void engineStart() {
    System.out.println("시동버튼을 눌렀습니다.");
    injectOil();
    injectGasoline();
    this.start = true;
    moveCylinder();
    System.out.println("시동이 걸렸습니다.");
}
  • 하지만 위 코드처럼 하나의 목적을 위해 관련있는 것들을 모아두는 캡슐화를 진행하면 engineStart 메서드만 실행해도 순서대로 진행하게 할 수 있다.
    -> 코드가 간결해지고 편의성 또한 증가
profile
백엔드 개발자
post-custom-banner

0개의 댓글