728x90
디자인 패턴이란?
- 객체 지향 프로그램을 어떻게 구현해야 좀 더 유연하고 재활용성이 높은 프로그램을 만들 수 있는지를 정리한 내용이 디자인 패턴 design pattern 입니다.
- 간단히 말해서 프로그램 특성에 따른 설계 유형을 이론화한 내용이며, 특정 알고리즘이나 프로그래밍 언어를 위한 라이브러리가 아니라 객체 지향으로 설계하는 방법을 설명한 것입니다.
- 그렇기 때문에 디자인 패턴은 자바, C++, C# 과 같은 다른 객체 지향 언어에도 적용하여 구현할 수 있습니다.
- 디자인 패턴 이론만으로도 책 한 권을 만들 수 있을 정도로 내용이 방대합니다.
싱글톤 패턴이란?
- 프로그램을 구현하다 보면 여러 개의 인스턴스가 필요한 경우도 있고 단 하나의 인스턴스만 필요한 경우도 있습니다.
- 객체 지향 프로그램에서 인스턴스를 단 하나만 생성하는 디자인 패턴을 싱글톤 패턴 singleton pattern 이라고 합니다.
- 우리가 여기서 살펴볼 싱글톤 패턴은 static 을 응용하여 프로그램 전반에서 사용하는 인스턴스를 하나만 구현하는 방식입니다.
- 실무나 여러 프레임워크에서 많이 사용하는 패턴이므로, 잘 익혀두어야 합니다.
싱글톤 패턴으로 회사 클래스 구현하기
- 어떤 회사를 객체 지향 프로그램으로 구현한다고 생각해봅시다.
- 직원은 여러명일테니 인스턴스를 여러 개를 생성합니다.
- 회사는 하나일테니 회사 인스턴스(객체)는 하나만 생성해야합니다.
- 단계적으로 Company 클래스를 만들어 봅시다.
단계 1 : 생성자를 private으로 만들기
- 생성자가 하나도 없는 클래스는 컴파일러가 자동으로 디폴트 생성자 코드를 넣어 줍니다.
- 그런데, 컴파일러가 만들어 주는 디폴트 생성자는 항상 public입니다.
- 생성자가 public이면 외부 클래스에서 인스턴스를 여러 개 생성할 수 있습니다.
- 따라서 싱글톤 패턴에서는 생성자를 반드시 명시적으로 만들고 그 접근 제어자를 private으로 지정해야 합니다.
- 그러면 컴파일러가 디폴트 생성자를 만들지 않고, 접근 제어자가 private 이므로 외부 클래스에서 마음대로 Company 인스턴스를 생성할 수 없게 됩니다.
- 즉 Company 클래스 내부에서만 이 클래스의 생성을 제어할 수 있습니다.
package singleton;
public class Company {
private Company() {
}
}
단계 2 : 클래스 내부에 static 으로 유일한 인스턴스 생성하기
- 단계 1에서 외부 클래스에서 인스턴스를 생성할 수 없도록 만들었습니다.
- 하지만 우리가 프로그램에서 사용할 하나의 인스턴스(회사 객체)가 필요합니다.
- 따라서 Company 클래스 내부에서 하나의 인스턴스를 생성해야 합니다.
- 이 회사 인스턴스(객체)는 프로그램 전체에서 사용할 유일한 인스턴스가 됩니다. 따라서 해당 인스턴스를 static 키워드를 포함한 상태로 만듭니다.
- 또한 외부에서 이 인스턴스에 접근하지 못하도록 private 키워드를 포함한 상태로 만들어야 인스턴스 오류를 방지할 수 있습니다.
package singleton;
public class Company {
private static Company instance = new Company();
private Company() {}
}
단계 3 : 외부에서 참조할 수 있는 public 메서드 만들기
- 이제 private 으로 선언한 유일한 인스턴스를 외부에서도 사용할 수 있도록 설정해야 합니다.
- 이를 가능하게 만드는 방법은 public 메서드(getter 메서드)를 생성하는 것입니다.
- 해당 메서드에서 유일하게 생성한 instance 를 반환해 줍니다.
- 이때 인스턴스를 반환하는 메서드는 반드시 static 으로 선언해야 합니다.
- 왜냐하면 getInstance( ) 메서드는 인스턴스 생성과 상관없이 호출할 수 있어야 하기 때문입니다.
package singleton;
public class Company {
private static Company instance = new Company();
private Company() {}
public static Company getInstance() {
if(instance == null) {
instance = new Company();
}
return instance;
}
}
단계 4 : 실제로 사용하는 코드 만들기
- 외부 클래스에서는 Comapny 를 생성할 수 없으므로 static 으로 제공되는 getInstance( ) 메서드를 호출합니다.
- Company.getInstance( ) 와 같이 호출하면 반환 값으로 유일한 인스턴스를 받아 옵니다.
- 다음 예제에서 유일한 인스턴스를 대입한 두 변수의 주소 값이 같은지 확인해 보면 true 가 출력되는 것을 볼 수 있습니다.
package singleton;
public class CompanyTest {
public static void main(String[] args) {
Company myCompany1 = Company.getInstance();
Company myCompany2 = Company.getInstance();
System.out.println(myCompany1 == myCompany2);
}
}
- myCompany1 과 myCompany2 를 비교해 보면 같은 참조 값을 가지는 동일한 인스턴스임을 알 수 있습니다.
- 또한 Company 클래스는 내부에 생성된 유일한 인스턴스 외에는 더 이상 인스턴스를 생성할 수 없습니다.
- 이와 같이 static 을 사용하여 유일한 객체를 생성하는 싱글톤 패턴을 구현할 수 있습니다.
연습하기
- 자동차 공장 클래스를 만들어 봅시다.
- 자동차 공장은 유일한 객체입니다.
- 여기서 생산되는 자동차는 100001 번 부터 시작해서 1씩 증가하면서 자동차 번호가 부여됩니다.
- ** Car, Carfactory, CarfactoryTest 클래스를 만들어서 프로그램을 구성합니다.
- 다음 CarFactoryTest.java 테스트 코드가 수행될 수 있도록 구현합니다.
package singleton;
public class CarFactoryTest {
public static void main(String[] args) {
CarFactory factory = CarFactory.getInstance();
Car mySonata = factory.createCar("mySonata");
Car yourSonata = factory.createCar("youSonata");
System.out.println(mySonata.getCarNum());
System.out.println(yourSonata.getCarNum());
System.out.println(mySonata.toString());
System.out.println(yourSonata.toString());
}
}
- ===== 정답 =====
package singleton;
public class Car {
String name;
static int serialNum = 10000;
int carNum;
int carCount=0;
public Car(String name) {
serialNum++;
this.carNum = serialNum;
this.name = name;
this.carCount++;
}
@Override
public String toString() {
return "Car [name=" + name + ", carNum=" + carNum + ", carCount=" + carCount + "대 생성]";
}
public int getCarNum() {
return carNum;
}
public void setCarNum(int carNum) {
this.carNum = carNum;
}
}
package singleton;
public class CarFactory {
private CarFactory() {} // 싱글톤 패턴 생성자
private static CarFactory instance = new CarFactory(); // 싱글톤 패턴 유일 인스턴스
public static CarFactory getInstance() { // 싱긅톤 패턴 유일 인스턴스 getter
return instance;
}
public Car createCar(String name) {
Car car = new Car(name);
return car;
}
}