의존성 주입과 싱글톤 패턴
- 의존성 주입은 객체 간의 결합도를 낮추기 위한 설계 패턴
- 객체 생성 및 관리를 담당하는 제 3자인 컨테이너가 객체 간의 의존성을 연결해주는 방식
- 객체는 자신이 필요로 하는 의존 객체가 어떤 것인지 알지 못하더라도, 외부(컨테이너, 의존성 주입자)에서 주입받은 객체를 사용하여 동작할 수 있다.
- 싱글톤 패턴은 객체를 하나의 인스턴스만 생성하여 공유하는 방식의 패턴이다.
- 의존성 주입을 통해 싱글톤 객체를 사용하 객체 간의 결합도를 낮출 수 있다.()
- 그렇기에 모듈들을 쉽게 교체할 수 있다→테스팅과 마이그레이션이 수월하다.
의존성 주입을 하지 않은 경우
// 싱글톤 클래스
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void doSomething() {
// some code
}
}
public class Client {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.doSomething();
// Singleton 객체에 의존하는 다른 객체 생성
OtherClass otherClass = new OtherClass();
otherClass.doSomethingElse();
}
}
// 싱글톤 클래스에 의존하는 클래스
public class OtherClass {
private Singleton singleton;
public OtherClass() {
// 인스턴스를 직접 생성
singleton = Singleton.getInstance();
}
public void doSomethingElse() {
singleton.doSomething();
}
}
- 위 코드에서는 OtherClass 클래스에서 Singleton 객체를 직접 생성하는 코드가 중복되어 나타나고
- Singleton 객체의 생성 및 관리에 대한 책임이 OtherClass 클래스로 넘어가게 되므로, 유지보수 및 확장성이 저하된다.
의존성 주입을 사용하는 경우
public class Singleton {
// same code
}
public class Client {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.doSomething();
// 생성자를 통해 의존성 주입
OtherClass otherClass = new OtherClass(singleton);
otherClass.doSomethingElse();
}
}
public class OtherClass {
private Singleton singleton;
// 생성자를 통해 의존성 주입
public OtherClass(Singleton singleton) {
this.singleton = singleton;
}
public void doSomethingElse() {
singleton.doSomething();
}
}
- **OtherClass**클래스에서 **Singleton**객체를 생성하지 않고, 생성자를 통해 의존성 주입을 받도록 변경
- 객체의 생성/관리 책임이 Client 클래스로 다시 돌아가므로 유지보수 및 확장성이 개선
팩토리 패턴
팩토리패턴이란?
- 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화
- 상위 클래스가 중요한 뼈대 결정 ↔ 하위 클래스에서 객체 생성에 관한 구체적 내용 결정
팩토리 패턴의 효용성
- 객체 생성 로직의 캡슐화 (+유연화)
- 객체 생성 과정을 외부로부터 감춘다.
- 사용하는 코드에서는 객체 생성 과정을 알 필요가 없어지며
- 객체 생성 과정이 변경되더라도 클라이언트 코드에 영향을 미치지 않음
- 객체 생성의 표준화
- 팩토리 패턴을 사용하면 객체를 생성하는 방식을 표준화할 수 있음
- 이를 통해 객체 생성을 일관성 있게 처리할 수 있으며 유지보수 및 확장성이 개선
- 코드 중복 제거
- 팩토리 패턴을 사용하면 객체 생성 로직을 중복으로 작성하는 것을 방지
public interface Animal {
void makeSound();
}
public class Client {
public static void main(String[] args) {
// dog 객체를 직접 생성
Animal dog = new Dog();
dog.makeSound();
}
}
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark!");
}
}
public interface Animal {
void makeSound();
}
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark!");
}
}
public class AnimalFactory {
public static Animal createAnimal(String type) {
switch (type) {
case "dog":
return new Dog();
default:
// some code
}
}
}
public class Client {
public static void main(String[] args) {
// 애니멀팩토리를 이용해 객체 생성
Animal dog = AnimalFactory.createAnimal("dog");
dog.makeSound();
}
}