디자인 패턴 [Android]
- 디자인 패턴
개발할 때 이용했던 디자인 패턴 있나요?
Singleton 많이 이용했습니다.
손 코딩 한 번 해보세요.
기술면접에서 매번 등장하는 디자인 패턴입니다.
짧게는 30분 길게는 2시간 정도의 기술면접 중 많은 시간을 할애할 수 없기에 보통 1~2개 정도 물어봐요.
Singleton이 많이 쓰이고 중요한 디자인 패턴이기 때문에 손 코딩했던 기억이 많네요.
(그놈의 손 코딩 누가 처음 시작한 건지..)
프로그램 개발에서 자주 나타나는 과제를 해결하기 위한 방법 중 하나로, 과거의 소프트웨어 개발 과정에서 발견된 설계의 노하우를 축적하여 이름을 붙여, 이후에 재이용하기 좋은 형태로 특정의 규약을 묶어서 정리한 것이다. 알고리즘과 같이 프로그램 코드로 바로 변환될 수 있는 형태는 아니지만, 특정한 상황에서 구조적인 문제를 해결하는 방식을 설명해 준다.
디자인 패턴이 뭐냐? 하는 원론적인 질문은 없었지만 OOP와 때려야 뗄 수 없는 SOLID에 대한 질문은 있었어요.
한 클래스는 하나의 책임만 가져야 한다.
소프트웨어 요소는 …… 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.”
“프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.”
“특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.”
프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안 된다.”
아래 패턴들을 다 알면 좋겠지만 너무 많네요.
싱글톤은 기본이고 그 외 평소 본인이 써본 패턴에 대해서는 공부합시다.
저는 팩토리, 어댑터, 데코레이션, 파사드 정도는 아네요.
추상 팩토리 패턴 : 동일한 주제의 다른 팩토리를 묶어 준다.
빌더 패턴 : 생성(construction)과 표기(representation)를 분리해 복잡한 객체를 생성한다
팩토리 메서드 패턴 : 생성할 객체의 클래스를 국한하지 않고 객체를 생성한다.
프로토타입 패턴 : 기존 객체를 복제함으로써 객체를 생성한다.
싱글톤 패턴 : 한 클래스에 한 객체만 존재하도록 제한한다.
어댑터 패턴 : 인터페이스가 호환되지 않는 클래스들을 함께 이용할 수 있도록, 타 클래스의 인터페이스를 기존 인터페이스에 덧씌운다.
브리지 패턴 : 추상화와 구현을 분리해 둘을 각각 따로 발전시킬 수 있다.
합성 패턴 : 0개, 1개 혹은 그 이상의 객체를 묶어 하나의 객체로 이용할 수 있다.
데코레이터 패턴 : 기존 객체의 매서드에 새로운 행동을 추가하거나 오버라이드 할 수 있다.
파사드 패턴 : 많은 분량의 코드에 접근할 수 있는 단순한 인터페이스를 제공한다.
플라이웨이트 패턴 : 다수의 유사한 객체를 생성·조작하는 비용을 절감할 수 있다.
프록시 패턴 : 접근 조절, 비용 절감, 복잡도 감소를 위해 접근이 힘든 객체에 대한 대역을 제공한다.
책임연쇄 패턴(Chain of responsibility) : 일련의 처리 객체들에 명령을 대행
커맨드 패턴 : 작업(action)과 매개변수를 묶어놓은 객체를 생성
해석자 패턴 (Interpreter pattern) : 특정 언어를 구현
반복자 패턴 (Iterator pattern) : 내부 구조를 드러내지 않고 객체의 구성요소들을 순차적으로 접근
중개자 패턴 (Mediator pattern) : 둘 이상의 클래스가 가지고 있는 매서드 들을 알고 있는 유일한 클래스로 클래스들을 느슨하게 연결
메멘토 패턴 (Memento pattern): 객체를 이전 상태로 복구하는 능력 제공
옵저버 패턴 : 옵저버 객체들이 이벤트를 볼 수 있게 하는 패턴
싱글턴 패턴은 해당 클래스의 인스턴스가 하나만 만들어진다.
어디서든지 그 인스턴스에 접근할 수 있도록 한다.
클래스에서 자신의 단 하나뿐인 인스턴스를 관리하도록 만들면 된다.
Android studio는 Singleton class를 생성해주는 메뉴가 기본적으로 있어요.
그만큼 많이 쓰인다는 반증이네요.
"java singleton"을 검색하면 수많은 작성법이 나와요.
작성법이 다양한 이유는 멀티스레딩 환경에서 동기화 문제 때문인데 결국 해결법은 두 가지예요.
Android studio에서 기본으로 제공하는 코드이고 작성법도 간단하네요.
하지만 클래스가 로딩될 때 무조건 인스턴스를 생성하기 때문에 꼭 필요한 클래스인지 다시 한번 생각해볼 필요가 있어요.
public class Singleton {
// private으로 Singleton클래스의 유일한 인스턴스를 저장하기 위한 정적 변수를 선언
private static Singleton ourInstance = new Singleton ();
// 생성자를 private로 선언했기 때문에 Singleton에서만 클래스를 만들 수 있다.
private Singleton () {
}
public static Singleton getInstance() {
// 클래스의 인스턴스를 리턴해 준다.
return ourInstance;
}
}
- DCL(Double-Checking Locking)을 사용하면, 일단 인스턴스가 생성되어 있는지 확인한 다음, 생성되어 있지 않았을 때만 동기화를 할 수 있다.
- volatile 키워드를 사용하여 멀티스레딩을 쓰더라도 uniqueInstance 변수가 Singleton 인스턴스로 초기화되는 과정이 올바르게 할 수 있다.
- DCL은 자바 1.4 이전 버전에서는 쓸 수 없다. (volatile 키워드는 자바 1.4 이하에서는 원자성 보존 범위가 달라요.)
첫 번째에 비해 코드가 더 복잡하네요. 대신 인스턴스를 필요할 때만 생성한다는 장점이 있어요.
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
// 이렇게 하면 처음에만 동기화된다
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
인터넷에 많은 자바 싱글톤 글들이 있는데 이 두 가지 방법 사이의 명확한 차이에 대해서는 찾기 힘들었어요.
그래서 아무것도 모르고 저는 DCL Singleton을 손 코딩했었네요..
앞으론 더 편한 첫 번째 방법으로 손 코딩해야겠어요.
자세한 설명은 아래 출처에 있습니다.
출처 : http://wiki.gurubee.net/pages/viewpage.action?pageId=1507372&