지난 포스팅에서 Naming Rule을 다루었는데, Naming Rule을 모르면 JAVA를 사용하지 못하는 것은 아니지만 Rule을 지키는 것이 협업에서 굉장히 중요하듯이, JAVA를 JAVA답게 사용하기 위하여 알아야하는 Class 개념이 있다.
① Message Passing
하나의 요구사항 != 하나의 클래스인데 클래스 간의 관계를 어떻게 설정해야 할까?
객체 지향에서는 다른 클래스에 직접 접근해서 변수를 건드릴 수 없다. 클래스 안에서 선언되는 변수는 반드시 같은 클래스 내부에 있는 메서드로만 핸들링해야 한다. 따라서 내가 필요한 데이터를 넘겨주는 메서드를 찾은 후 리턴 값을 받아야 한다.
이처럼 객체 지향 프로그래밍에서 객체 간 상호 작용을 위해 메시지를 전달하는 것을 message passing이라고 한다. 메시지 전달을 통해 객체 간의 상호작용이 이루어지기 때문에 객체 간의 결합도가 낮아져 캡슐화, 추상화 및 다형성을 가능하게 한다.
② 생성자
class Bank {
final int myMoney = 1000;
final int numOfCoin = 20;
public Bank(int money, int coin) {
myMoney = money;
numOfCoin = coin;
}
}
클래스 내부의 변수를 final로 선언하면 값을 바꿀 수 없기 때문에 생성과 동시에 초기화를 해야 한다. 하지만 코드의 확장성을 위해서는 인스턴스를 생성하면서 전달받은 파라미터로 값을 초기화하는 것이 좋다. 이를 위해 final을 지우면 코드의 안정성이 떨어진다.
class Bank {
int myMoney;
int numOfCoin;
public Bank(int money, int coin) {
myMoney = money;
numOfCoin = coin;
}
}
이 상황에서 필요한 것이 바로 "생성자"다. 생성자(Constructor)란 객체가 생성될 때 호출되는 메서드로, 생성자는 final로 선언된 상수의 값을 한번 변경할 수 있기 때문에 객체 생성 시 필요한 초기화 작업을 수행한다. 생성자는 클래스와 같은 이름으로 정의되며 반환값이 없다. 추후에 다루겠지만, 자바에서는 생성자를 오버 로딩하여 여러 개의 생성자를 정의할 수 있다. 생성자를 명시적으로 정의하지 않으면 컴파일러가 자동으로 default 생성자를 추가한다.
그런데, Car myCar = new Car()이라는 코드에서 Car 옆에 소괄호를 쓰는 이유는?
Car myCar = new Car();에서 Car()은 생성자(constructor)를 호출하기 위한 것이다. new Car에서 Car 클래스의 인스턴스를 생성하고, Car()에서 생성자를 호출하여 해당 인스턴스를 초기화한다. 생성자가 객체를 생성할 때 호출되어야 하기 때문에 클래스 이름과 생성자의 이름이 같아야 하는 것이다.
※ 인스턴스 변수를 초기화시키는 방법
1. =으로 초기화
2. 생성자로 초기화
3. setter 메서드를 사용해서 초기화
java에서 변수나 상수에 값을 넣을 때 사용하는 메서드는 set, 빼낼 때는 get으로 시작하는 메서드를 사용하고 getter, setter라고 부른다. 하지만 setter로는 final로 선언된 상수를 초기화할 수 없다.
③ 접근 제어
class Bank {
int myMoney;
int numOfCoin;
public Bank() {...}
}
class Customer {
public static void main(String[] args) {
Bank bank = new Bank();
bank.myMoney += 500;
}
}
위 코드를 보면, main 메서드에서 Bank 클래스의 인스턴스 변수(myMoney)에 직접 접근하여 값을 수정했다. 이는 돈을 대출하는 클래스를 잘 만들었는데, 돈을 받는 쪽에서 가격을 잘못 입력하는 경우와 같다. Java에서는 한 클래스에서 다른 클래스의 변수에 직접 접근하는 것을 권장하지 않는다. Java에는 문제 예방을 위해 일부러 compile time error를 만들어내는 테크닉들이 있는데, 그중 하나가 접근 제어 지시자를 사용하는 것이다.
※ Access Control Specifier, 접근 제어 지시자
Java에서는 클래스, 변수, 메서드 앞에 접근 제어 지시자를 사용하여 접근 범위를 제어할 수 있다.
1. private : private이 붙은 변수나 메서드는 같은 클래스 내부에서만 접근이 가능하다. 이를 통해 정보 은닉 (Information hiding)이 가능하며, message passing을 통해서만 변수를 조작할 수 있도록 클래스 내부의 인스턴스 변수에는 private을 붙이는 것이 좋다.
2. default : default는 public, protected, private가 붙어있지 않은 것으로, 같은 패키지 내부에서만 접근이 가능하다.
3. protected : protected는 default의 확장으로, 다른 패키지더라도 상속이 걸린 클래스라면 접근이 가능하다.
4. public : public 접근 제어 지시자는 접근 제한이 없다.
※ singleton pattern
public class A {
private A() {
// code
}
}
위의 코드는 클래스 앞에 public이 붙어 있으므로 누구나 접근이 가능하다고 생각할 수 있지만, 생성자를 호출할 수 없으므로 인스턴스를 만들 수 없다. 다른 클래스에서 A() 메서드에 접근할 수 없기 때문에 A rv = new A();를 적으면 compile error가 뜬다. 즉, 위의 형태는 같은 클래스 내부에서만 접근 가능하다.
Singleton pattern은 오직 하나의 인스턴스만 생성되도록 하는 디자인 패턴이다. 외부에서 생성자를 호출할 수 없고, 클래스 내부에서 유일한 인스턴스를 생성하고 반환하는 메서드를 호출할 수 있다.
Singleton pattern을 사용하면 객체 생성과 소멸에 대한 관리를 효율적으로 할 수 있고, 하나의 인스턴스만 생성되므로 여러 곳에서 공유해서 사용해야 하는 경우에도 문제가 발생하지 않는다.
'JAVA' 카테고리의 다른 글
[JAVA] Chapter 8. Class Variable & Class Method (0) | 2023.07.10 |
---|---|
[JAVA] Chapter 7. Class (3) (0) | 2023.07.09 |
[JAVA] Chapter 7. Class (1) (0) | 2023.07.07 |
[JAVA] Chapter 6. Method (0) | 2023.07.06 |
[JAVA] Chapter 5. Control (0) | 2023.07.05 |
댓글