내가 프로젝트 하면서 느낀게 자바에서 객체 공유라는 것은 정말로 중요한 것 같다.
JAVA를 공부하면서 인터페이스, 상속, 의존성 주입(DI) 같은 것을 배웠긴하나 실전에서 쓸라고 하니깐 전혀 생각이 안났다.
하지만 실전 적용해보니 정말 코드 자체가 깔끔해지고.. 암튼 속이 시원했다.
위에 말했다시피 객체를 공유하려면, N개의 클래스가 동일한 객체를 참조하도록 해야하는데, 이를 위해 보통 '주입'이라는 방법으로 객체를 전달한다. 1대1 클래스 간에는 new 키워드로 인스턴스를 생성해도 되지만, 클래스가 3개 이상부터 서로 간에 데이터를 공유하거나 공용 메서드를 사용해야 할 경우, 객체 간의 관계를 명확하게 하고, 서로의 의존성을 관리하는 방법이 중요하다 생각한다!!
주입 방식은 객체가 필요로 하는 다른 객체를 직접 new 키워드로 생성하지 않고 외부에서 주입 받는 경우다. new 키워드를 사용하면 새로운 객체(x002)가 만들어지는 것이기 때문에 원래 기존에 있던 객체(x001)가 담고 있는 저장된 배열, 데이터들을 받지 못하는 사태가 발생한다.
ex) 객체1(x001)에는 [1,2,3,4,5] 배열이 담겨져 있었다. 하지만 new 키워드를 사용하면 객체2(x002)가 생성되기 때문에 객체2(x002)에는 [ ]배열이 될 수 밖에 없다.
주입에는 방법이 2가지가 있따.
1. 생성자 주입 : 객체가 생성될 때 필요한 의존 객체를 생성자한테 주입 받는 방식
예제) 자동차와 엔진
// 1. Engine 클래스 (의존 대상)
public class Engine {
public void start() {
System.out.println("엔진이 시작됩니다.");
}
}
// 2. Car 클래스 (의존 객체)
public class Car {
private final Engine engine;
// 생성자 주입
public Car(Engine engine) {
this.engine = engine;
}
public void startCar() {
System.out.println("자동차가 출발합니다.");
engine.start();
}
}
// 3. Main 클래스 (의존성 관리 및 실행)
public class Main {
public static void main(String[] args) {
// Engine 객체 생성
Engine engine = new Engine();
// Car 객체 생성 시 Engine 객체를 주입
Car car = new Car(engine);
// 자동차 작동
car.startCar();
}
}
- Engine 클래스는 자동차(Car)의 동작에 필요한 엔진 기능을 제공.
- Car 클래스는 생성자를 통해 Engine 객체를 전달.
• 이렇게 하면 Car는 어떤 Engine 객체를 사용할지 직접 생성하지 않고 외부에서 주입. - Main 클래스는 의존성(Engine)을 생성한 후, Car에 전달.
2. Setter 주입 : 객체가 생성된 후, 세터 메서드를 통해 의존 객체를 주입 받는 방식
의존성 주입 예제(쇼핑몰 주문 시스템)
1. 주문 처리(OrderService)
: 주문 요청을 처리하고 결과를 반환
2. 재고 관리(InventoryService)
: 상품의 재고를 확인하고 업데이트
3. 결제 처리(PaymentService)
: 결제를 처리하고 반환
4. 데이터 저장소(Database)
: 주문 및 재고 데이터를 저장/조회
1. Database (공용 데이터 관리)
public class Database {
private Map<String, Integer> inventory = new HashMap<>(); // 상품명, 재고
private Map<Integer, String> orders = new HashMap<>(); // 주문번호, 주문정보
private int orderId = 1;
public Database() {
// 초기 재고 설정
inventory.put("Apple", 10);
inventory.put("Banana", 15);
inventory.put("Orange", 5);
}
// 재고 조회
public int getStock(String item) {
return inventory.getOrDefault(item, 0);
}
// 재고 감소
public void reduceStock(String item, int quantity) {
inventory.put(item, inventory.get(item) - quantity);
}
// 주문 저장
public void saveOrder(String orderDetails) {
orders.put(orderId++, orderDetails);
}
// 주문 조회
public Map<Integer, String> getOrders() {
return orders;
}
}
public class InventoryService {
private final Database database;
public InventoryService(Database database) {
this.database = database;
}
public boolean checkStock(String item, int quantity) {
return database.getStock(item) >= quantity;
}
public void updateStock(String item, int quantity) {
database.reduceStock(item, quantity);
}
}
public class PaymentService {
public boolean processPayment(String paymentMethod, double amount) {
// 간단히 결제가 항상 성공한다고 가정
System.out.println("결제 성공: " + paymentMethod + "으로 " + amount + "원 결제 완료");
return true;
}
}
public class OrderService {
private final InventoryService inventoryService;
private final PaymentService paymentService;
private final Database database;
public OrderService(InventoryService inventoryService, PaymentService paymentService, Database database) {
this.inventoryService = inventoryService;
this.paymentService = paymentService;
this.database = database;
}
public void placeOrder(String item, int quantity, String paymentMethod, double amount) {
// 재고 확인
if (!inventoryService.checkStock(item, quantity)) {
System.out.println("재고 부족: " + item);
return;
}
// 결제 처리
if (!paymentService.processPayment(paymentMethod, amount)) {
System.out.println("결제 실패");
return;
}
// 재고 업데이트
inventoryService.updateStock(item, quantity);
// 주문 저장
String orderDetails = "상품: " + item + ", 수량: " + quantity + ", 결제 금액: " + amount;
database.saveOrder(orderDetails);
System.out.println("주문 완료: " + orderDetails);
}
public void viewOrders() {
System.out.println("모든 주문 내역: " + database.getOrders());
}
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 공용 Database 객체 생성
Database database = new Database();
// Service 객체에 Database 주입
InventoryService inventoryService = new InventoryService(database);
PaymentService paymentService = new PaymentService();
OrderService orderService = new OrderService(inventoryService, paymentService, database);
Scanner scanner = new Scanner(System.in);
// 주문 예제 실행
System.out.println("상품 주문 시스템입니다.");
while (true) {
System.out.println("1. 주문하기 | 2. 주문 내역 보기 | 3. 종료");
int choice = scanner.nextInt();
scanner.nextLine(); // 개행문자 제거
if (choice == 1) {
System.out.print("상품명: ");
String item = scanner.nextLine();
System.out.print("수량: ");
int quantity = scanner.nextInt();
scanner.nextLine();
System.out.print("결제 방식: ");
String paymentMethod = scanner.nextLine();
System.out.print("결제 금액: ");
double amount = scanner.nextDouble();
scanner.nextLine();
orderService.placeOrder(item, quantity, paymentMethod, amount);
} else if (choice == 2) {
orderService.viewOrders();
} else if (choice == 3) {
System.out.println("시스템을 종료합니다.");
break;
} else {
System.out.println("잘못된 선택입니다. 다시 시도해주세요.");
}
}
scanner.close();
}
}
실행 흐름
1. Main 클래스는 Database 객체를 생성.
2. InventoryService, PaymentService, OrderService는 각각 Database를 주입받아 필요할 때 데이터를 조회하거나 수정.
3. 사용자는 상품 주문을 하고, 서비스 클래스들이 협력하여 주문 처리와 결과를 출력.
이 부분을 너무 간과하고 여태 코드를 짜고 공부를 했나보다.. 오늘 Java 주입에 대한 중요성을 크게 깨달은 날이니 항상 기억하고 다니자..!
'Back-End > JAVA' 카테고리의 다른 글
| 오버로딩과 this() (0) | 2024.11.16 |
|---|---|
| 기본형 변수와 참조형 변수 (0) | 2024.11.16 |
| ENUM (4) | 2024.11.15 |
| 배열 (0) | 2024.11.08 |
| 변수 스코프와 형변환 (1) | 2024.11.08 |