Search

백기선 GoF 강의

디자인패턴.pdf
4975.8KB
design-patterns.zip
330.0KB

싱글톤 패턴

인스턴스를 오직 한개만 제공하는 클래스
환경 세팅에 대한 정보 등, 인스턴스가 여러 개 일 때 문제가 생길 수 있는 경우가 있다.
인스턴스를 오직 한개만 만들어 제공하는 클래스가 필요하다
게임에 대한 설정

핵심

private 생성자 + static한 생성자
public class Settings(){ private static Settings instance; private Settings(){} public static Settings getInstance(){ if(instance == null){ return new Settings(); } return instance; } }
Java
복사
→ 이 방법은 쓰레드에 안전하지 않다.
왜냐?
생성되는 순간에 instance를 평가한다면, 아직 만들어지지 않았기 때문에 또 만들어진다.
그러면 가장 쉬운 방법은 getInstance에 synchronized라는 키워드를 만들자.
public class Settings(){ private static Settings instance; private Settings(){} public static synchronized Settings getInstance(){ if(instance == null){ return new Settings(); } return instance; } }
Java
복사
→ 이러면 성능에 무리가 올 수 있다. lock을 걸기 때문에
뿐만 아니라 eager initialization을 이용하자. if 객체 생성 비용이 크지 않을 때
미리 만드는게 단점, 즉 생성할 때 꽤 시간이 걸리고 메모리를 많이 먹는다면, 이라면 이러면 좀...
그러면 double checked locking을 하자.
public class Settings(){ private static volatile Settings instance; private Settings(){} public static Settings getInstance(){ if(instance == null){ synchronized(Settings.class){ if(instance == null){ instance = new Settings(); } } } return instance; } }
Java
복사
→ getInstance()를 매번 호출할 때마다, synchronized를 쓰진 않는다.
인스턴스가 만약에 있으면 그냥 instance를 return하기 때문
굉장히 복잡한 방법이다.
→ 단순하게 안전하게 구현하자!
static inner 클래스 사용하기
public class Settings(){ private Settings(){ } private static class SettingsHolder{ private static final Settings INSTANCE = new SETTINGS(); } public static Settings getInstance(){ return SettingsHolder.INSTANCE; } }
Java
복사
lazy 로딩이 가능하다.
멀티쓰레드에서 안전하다.
⇒ static한 메서드를 통해 생성하고, static한 필드를 이용하기 때문에

싱글톤 깨트리기~

1.
리플렉션을 사용하자 ⇒ 리플렉션을 사용해서 private한 메서드에 접근해서 생성자를 호출하자
2.
직렬화 & 역직렬화, implements Serializable ⇒ 역직렬화를 하면 반드시 생성자를 다시 호출하기 때문에 다른 객체가 된다.

Enum을 쓰자

Enum 같은 경우도 프로퍼티와 메소드를 정의할 수 있기 때문에 써도 된다.
⇒ 리플렉션에 안전한 코드가 된다.

어디에 쓰이나?

1.
Java의 Runtime이라는 인스턴스
a.
⇒ 미리 만들어놨기 때문에 쓰레드 safe하다.
b.
자바 앱이 실행되고 있는 실행환경에 대한 얘기
2.
스프링에서는 ApplicationContext
3.
다른 디자인 패턴의 구현체 일부

팩토리 메소드 패턴

구체적으로 어떤 인스턴스를 만들지는 서브 클래스가 정한다.
인스턴스를 생성하는 책임을 구체적인 클래스가 아니라 추상적인 인스턴스의 메서드로 감싸는 것이다.
Creator, Product라는 인터페이스를 일단 만들고
거기서 ConcreteCreator를 구현하고 거기서 ConcreteProduct를 생산한다.
기존에 if-else로 객체가 생성되는 경우, 팩토리가 변경에 대해서 닫혀있지 않다.
요구 사항에 대해서 계속 바뀌기 때문
⇒ 근데 클라이언트 코드는 바뀌지 않느냐..? 바뀐거 아님?
⇒ 맞다 하지만, 의존성 주입 위주로 하면 클라이언트 코드도 최소한으로 줄일 수 있음

예시들

1.
JAVA : Calendar, NumberFormat
2.
Spring : BeanFactory → CreatorInterface이다.
a.
이거에 해당하는 여러 구현체들이 있다. ClassPathXmlApplicationContext 등등