Step 4 요구사항을 읽어보니 새로운 기능을 추가하는 것이 아니라, 이미 만들어진 객체들을 더 안전하게 만드는 데 있다고 생각했다.
필드에 직접 접근하지 못하도록 막고, Getter 통해서만 데이터를 읽게 하고, 객체의 내부 상태를 외부에서 함부로 변경하지 못하게 하는 캡슐화 개념을 코드로 직접 적용해보는 단계라고 생각했다.
객체 내부 상태를 객체 스스로 보호하도록 설계
Product 클래스에서는 상품의 기본 정보와 재고를 필드로 가지고 있다. 모든 필드를 private로 선언하고 외부에서는 getter를 통해서만 값을 확인할 수 있도록 했다.
package kr.spartaclub.com.example.commerce;
public class Product {
private final String name;
private final int price;
private final String description;
private int stock;
public Product(String name, int price, String description, int stock) {
this.name = name;
this.price = price;
this.description = description;
this.stock = stock;
}
public String getName() { return name; }
public int getPrice() { return price; }
public String getDescription() { return description; }
public int getStock() { return stock; }
}
Category 클래스는 카테고리 이름과 해당 카테고리에 속한 상품 목록을 관리한다.
상품 리스트는 외부에서 직접 수정되지 않도록 하기 위해 getter에서 새로운 리스트를 반환하도록 수정했다.
외부 코드에서 내부 컬렉션을 변경하는 상황 방지 가능
package kr.spartaclub.com.example.commerce.step4;
import kr.spartaclub.com.example.commerce.Product;
import java.util.List;
// 하나의 카테고리(전자제품, 의류, 식품)를 표현하는 객체 - 카테고리 이름과 해당 카테고리에 속한 상품 목록을 함께 관리한다.
public class Category {
// 카테고리 이름 - 외부에서 직접 변경하지 못하도록 private + final
private final String name;
// 해당 카테고리에 속한 상품 리스트 - 외부에서 직접 접근하지 못하도록 private으로 선언
private final List<Product> products;
/**
* Category 생성자
* @param name 카테고리 이름
* @param products 해당 카테고리에 포함될 상품 목록
*/
public Category(String name, List<Product> products) {
this.name = name;
this.products = products;
}
//카테고리 이름 조회
public String getName() {
return name;
}
// 카테고리에 속한 상품 목록 조회
public List<Product> getProducts() {
return products;
}
}
Customer 클래스는 고객의 이름, 이메일, 등급, 누적 주문 금액 정보를 가진다.
고객 정보를 안전하게 보관하기 위해 모든 필드를 private 으로 선언하고 getter 만 제공하도록 구현했다.
package kr.spartaclub.com.example.commerce.step4;
// Customer 클래스
// 고객 정보를 저장하는 객체
public class Customer {
// 고객 이름과 이메일은 생성 후 변경되지 않으므로 final
private final String name;
private final String email;
// 고객 등급과 누적 주문 금액
private String grade;
private int totalOrderAmount;
// Customer 생성자
public Customer(String name, String email) {
this.name = name;
this.email = email;
this.grade = "BRONZE";
this.totalOrderAmount = 0;
}
// Getter 메서드만 제공하여 외부에서 직접 필드 수정 불가
public String getName() { return name; }
public String getEmail() { return email; }
public String getGrade() { return grade; }
public int getTotalOrderAmount() { return totalOrderAmount; }
}

캡슐화를 적용한 이후에도 Step3에서 구현했던 기능들은 정상적으로 동작하는 것을 확인할 수 있었다.
객체 내부 구현을 수정했지만 외부에서는 동일한 방식으로 객체를 사용할 수 있었고, 이를 통해 캡슐화의 장점을 직접 체감할 수 있었다.