
프로그램을 만들다 보면 “어디서든 같은 객체 하나만 공유”해야 하는 경우가 있다.
만약 이런 객체를 new로 계속 생성하면, 관리 데이터가 각각 분리되어 흐름이 꼬이고 상태 관리가 어려워진다.
싱글톤 패턴은 이런 문제를 해결하기 위해 객체를 단 하나만 생성하고, 그 객체를 전역 공유하는 구조이다.
싱글톤은 보통 다음 3가지를 세트로 가진다.
이 구조 덕분에 어떤 코드에서 접근하더라도 항상 “같은 객체”를 받게 된다.
차량 정보를 담는 클래스이다. Lombok을 사용해서 반복 코드를 줄이고, Builder로 객체 생성 가독성을 올린 구조이다.
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@Data
@AllArgsConstructor
@Builder
public class Car {
private int carNumber;
private String company;
private String model;
}
KIA 클래스는 “주차장 관리소”처럼 동작한다.
주요 데이터는 다음과 같다.
그리고 가장 중요한 포인트는 생성자를 private으로 막고, getInstance()로만 객체를 얻도록 만든 것이다.
public class KIA {
private static KIA instance;
private Car[] carArray;
private int autoCode;
private KIA() {
carArray = new Car[5];
autoCode = 20260000;
}
public static KIA getInstance() {
if (instance == null) {
instance = new KIA();
}
return instance;
}
public Car inputCar(String company, String model) {
Car car = Car.builder()
.model(model)
.company(company)
.carNumber(++autoCode)
.build();
for (int i = 0; i < carArray.length; i++) {
if (carArray[i] == null) {
carArray[i] = car;
System.out.println("입고 완료");
return car;
}
}
autoCode--;
System.out.println("만차입니다.");
return null;
}
public void outputCar(int carNumber) {
for (int i = 0; i < carArray.length; i++) {
Car car = carArray[i];
if (car == null) continue;
if (car.getCarNumber() == carNumber) {
carArray[i] = null;
System.out.println("출차 완료");
return;
}
}
System.out.println("차량 없음");
}
public void parkList() {
boolean empty = true;
for (int i = 0; i < carArray.length; i++) {
Car car = carArray[i];
if (car == null) continue;
empty = false;
System.out.println("번호: " + car.getCarNumber());
System.out.println("제조사: " + car.getCompany());
System.out.println("모델: " + car.getModel());
System.out.println();
}
if (empty) {
System.out.println("주차된 차량이 없습니다.");
}
}
}
getInstance()는 instance가 null일 때만 new KIA()를 실행한다.
그래서 아래처럼 여러 번 받아도 모두 같은 객체가 나온다.
public class SingletonMain {
public static void main(String[] args) {
KIA kia1 = KIA.getInstance();
KIA kia2 = KIA.getInstance();
KIA kia3 = KIA.getInstance();
System.out.println(kia1);
System.out.println(kia2);
System.out.println(kia3);
}
}
출력된 주소값(참조값)이 전부 같다면, 싱글톤이 정상적으로 동작하는 것이다.
public class SingletonMain {
public static void main(String[] args) {
KIA kia1 = KIA.getInstance();
KIA kia2 = KIA.getInstance();
KIA kia3 = KIA.getInstance();
System.out.println(kia1);
System.out.println(kia2);
System.out.println(kia3);
System.out.println(kia1.inputCar("kia", "morning"));
System.out.println(kia1.inputCar("kia", "k3"));
System.out.println(kia1.inputCar("kia", "k5"));
System.out.println(kia1.inputCar("kia", "k7"));
System.out.println(kia1.inputCar("kia", "k8"));
System.out.println(kia1.inputCar("kia", "k9"));
kia1.parkList();
kia1.outputCar(20260001);
System.out.println(kia1.inputCar("kia", "K7"));
System.out.println(kia1.inputCar("kia", "K8"));
}
}
즉, 싱글톤은 static을 이용해서 “유일 객체”를 저장하고 관리하는 패턴이다.
싱글톤은 단순히 “객체를 하나만 만들기”가 아니라, 프로그램 전체에서 같은 상태를 공유해야 하는 상황에서 구조를 안정적으로 유지하는 패턴이라는 걸 느꼈다.
특히 주차장처럼 데이터가 한 곳에 모여야 하는 구조에서는 new로 객체를 여러 번 만들면 관리 자체가 깨지기 때문에, getInstance()로 동일 객체를 공유하는 방식이 핵심이라는 점이 확실해졌다.
다음 단계로는 배열 대신 List로 확장하거나, 싱글톤의 스레드 안전성까지 고려하는 방식도 이어서 정리해보면 좋을 것 같다.