분류 기타

모든 개발자가 알아야 할 3 가지 유형의 디자인 패턴 - 각각의 코드 예제

컨텐츠 정보

  • 조회 201 (작성일 )

본문

디자인 패턴이란 무엇입니까? 


디자인 패턴은 소프트웨어 엔지니어가 자주 접하는 반복적인 문제에 대한 설계 수준의 솔루션입니다. 코드가 아닙니다. 반복합니다. 코드가 아닙니다. 이 문제를 해결하고 솔루션을 설계하는 방법에 대한 설명과 같습니다.


이러한 패턴을 사용하는 것은 솔루션의 디자인이 매우 시용되고 테스트되어 최종 코드의 가독성을 높이기 때문에 좋은 방법입니다. 디자인 패턴은 Java와 같이 OOP 언어에 의해 생성되고 사용되는 경우가 많습니다. 여기서는 대부분의 예제가 작성됩니다.


디자인 패턴의 유형 


현재 발견 된 약 26 개의 패턴이 있습니다 (거의 모든 것을 할 것이라고 생각합니다 ...).


이 26개 유형은 3 가지 유형으로 분류 할 수 있습니다.


1. 창조(Creational) :이 패턴은 클래스 인스턴스화를 위해 설계되었습니다. 클래스 생성 패턴 또는 객체 생성 패턴일 수 있습니다.


2. 구조(Structural) :이 패턴은 class의 구조와 구성과 관련하여 고안되었습니다. 이러한 패턴의 주요 목표는 구성을 많이 변경하지 않고 관련된 클래스의 기능을 향상 시키는 것입니다.


3. 행동(Behavioral) :이 패턴은 한 클래스가 다른 사람들과 어떻게 커뮤니케이션하는지에 따라 설계되었습니다.


이 글에서는 각 분류 된 유형에 대해 하나의 기본 디자인 패턴을 살펴 보겠습니다.


유형 1 : 창조성 - 싱글 톤 디자인 패턴 


싱글톤 디자인 패턴은 클래스의 하나의 인스턴스만 생성하고 하나의 글로벌 액세스 포인트를 해당 객체에 제공하는 것을 목표로 하는 창조적인 패턴입니다. Java에서 이러한 클래스의 일반적으로 사용되는 예는 Calendar입니다. 여기서 해당 클래스의 인스턴스를 만들 수 없습니다. 또한 자체 getInstance() 메서드를 사용하여 객체를 가져옵니다.


싱글 톤 디자인 패턴을 사용하는 클래스에는,


singleton-class-diagram.png 

Singleton Class Diagram


  • 클래스의 유일한 인스턴스를 보유하는 개인 정적 변수입니다.
  • private 생성자이므로 다른 곳에서는 인스턴스화 할 수 없습니다.
  • 클래스의 단일 인스턴스를 반환하는 public static 메서드입니다.


싱글톤 디자인에는 여러 가지 구현이 있습니다.


1. 열의 인스턴스화

2. 지연 인스턴스화

3. 스레드 안전 인스턴스화


열망하는 비버? 


public class EagerSingleton {
	// create an instance of the class.
	private static EagerSingleton instance = new EagerSingleton();

	// private constructor, so it cannot be instantiated outside this class.
	private EagerSingleton() {  }

	// get the only instance of the object created.
	public static EagerSingleton getInstance() {
		return instance;
	}
}

이 인스턴스 유형은 변수 인스턴스의 인스턴스가 모든 메소드 외부에서 발생하기 때문에 클래스 로드 중에 발생합니다. 이 클래스가 클라이언트 응용 프로그램에서 전혀 사용되지 않으면 상당한 단점이 있습니다. 비상 계획은 이 클래스가 사용되지 않는 경우 지연 초기화 (Lazy Instantiation)입니다.


게으른 나날들 ? 


위의 구현과 큰 차이는 없습니다. 가장 큰 차이점은 정적 변수는 처음에는 null로 선언되며, 인스턴스 변수가 검사 당시 null 인 경우에만 - getInstance() 메서드 내에서 인스턴스화 됩니다.


public class LazySingleton {
	// initialize the instance as null.
	private static LazySingleton instance = null;

	// private constructor, so it cannot be instantiated outside this class.
	private LazySingleton() {  }

	// check if the instance is null, and if so, create the object.
	public static LazySingleton getInstance() {
		if (instance == null) {
			instance = new LazySingleton();
		}
		return instance;
	}
}

하나의 문제는 해결되지만 다른 문제는 여전히 존재합니다. 두 개의 서로 다른 클라이언트가 밀리세컨드까지 동시에 Singleton 클래스에 액세스하면 어떻게 될까요? 글쎄, 그들은 인스턴스가 동시에 null인지 확인하고, 사실을 발견 할 것이므로 두 클라이언트가 각 요청에 대해 클래스의 두 인스턴스를 생성합니다. 이 문제를 해결하려면 스레드 안전 인스턴스화가 구현되어야 합니다.


(쓰레드) 안전은 열쇠입니까? 


Java에서 synchronized 키워드는 메서드 또는 객체에서 스레드 안전성을 구현하는 데 사용되므로 한 번에 하나의 스레드 만 특정 리소스에 액세스합니다. 클래스 인스턴스화는 동기 블록 내에 놓여 지므로 주어진 시간에 한 클라이언트가 메소드에 액세스 할 수 있습니다.


public class ThreadSafeSingleton {
	// initialize the instance as null.
	private static ThreadSafeSingleton instance = null;

	// private constructor, so it cannot be instantiated outside this class.
	private ThreadSafeSingleton() {  }

	// check if the instance is null, within a synchronized block. If so, create the object
	public static ThreadSafeSingleton getInstance() {
		synchronized (ThreadSafeSingleton.class) {
			if (instance == null) {
				instance = new ThreadSafeSingleton();
			}
		}
		return instance;
	}
}

동기화 된 메서드의 오버 헤드가 높기 때문에 전체 작업의 성능이 저하됩니다.


예를 들어 인스턴스 변수가 이미 인스턴스화 된 경우 클라이언트가 getInstance() 메소드에 액세스 할 때마다 동기화 된 메소드가 실행되고 성능이 떨어집니다. 이것은 인스턴스 변수의 값이 null인지 확인하기 위해 발생합니다. 

그것이 발견되면 메소드를 종료합니다.


이 오버 헤드를 줄이기 위해 이중 잠금이 사용됩니다. 동기화 된 메서드 앞에 검사가 사용되며 값이 null 인 경우 동기화 된 메서드가 실행됩니다.


// double locking is used to reduce the overhead of the synchronized method
public static ThreadSafeSingleton getInstanceDoubleLocking() {
	if (instance == null) {
		synchronized (ThreadSafeSingleton.class) {
			if (instance == null) {
				instance = new ThreadSafeSingleton();
			}
		}
	}
	return instance;
}

유형 2 : 구조 - 장식자(Decorator) 디자인 패턴


Decorator Pattern을 사용해야 하는 이유와 장소에 대해 더 자세히 설명 할 수 있는 작은 시나리오를 제공 할 것입니다.


커피 숍을 소유하고 있고 초보자처럼 두 가지 유형의 일반 커피 (집과 짙은 로스트)로 시작한다고 가정 해 보겠습니다. 귀하의 결제 시스템에는 음료수 추상 클래스를 상속하는 다양한 커피 블렌드를 위한 클래스가 있었습니다. 사람들은 실제로 와서 커피를 먹기 시작합니다. 그 다음에 신이 금지하는 커피 newbs가 있습니다. 설탕이나 우유가 필요합니다. 커피에 대한 그런 travesty! ??


이제는 메뉴와 불행히도 결제 시스템에서 이 두 부가 기능을 추가로 가져야 합니다. 원래 IT 직원은 설탕을 포함한 두 가지 커피, 그리고 다른 우유를 위한 하위 클래스를 만들 것입니다. 그렇다면 고객이 항상 옳기 때문에 다음과 같은 두려운 말을 듣습니다.


"설탕과 함께 우유 커피를 마실 수 있습니까?" 


??? 


귀하의 청구 시스템이 귀하의 얼굴을 다시 웃게 됩니다. 글쎄, 다시 드로잉 보드에 ....


IT 담당자는 우유 커피에 설탕을 추가하여 각 상위 커피 클래스에 또 다른 하위 클래스로 추가합니다. 나머지 달은 매끄러운 항해입니다. 사람들이 커피를 갖기 위해 일렬로 세우고 있습니다. 실제로 돈을 벌고 있습니다. ??


세상은 당신을 다시 한번 반대합니다. 경쟁자가 거리를 가로 질러 열리는데 커피 종류는 4 가지가 아니라 10 가지가 넘습니다. ?


당신은 그 이상을 사고, 더 나은 커피를 직접 팔고, 그때 당신은 그 징역 시스템을 업데이트 하는 것을 잊었다는 것을 기억하십시오. 새로운 커피 블렌드와 함께 모든 추가 기능의 모든 조합에 대해 무한대의 하위 클래스를 만들 수는 없습니다. 말할 것도 없이, 최종 시스템의 크기. ??


적절한 청구 시스템에 실제로 투자 할 시간. 당신은 새로운 IT 인력을 찾고 있습니다. 그들은 실제로 무엇을 하고 있는지를 알고 있습니다.


"왜, 장식기 패턴을 사용하면 훨씬 더 쉽고 작을 것입니다."


지구상에 뭐야? 


데코레이터 디자인 패턴은 상속, 구성 또는 둘 다 여부에 관계없이 클래스의 실제 구조를 처리하는 구조적 범주로 분류됩니다. 이 디자인의 목표는 런타임에 객체의 기능을 수정하는 것입니다. 이것은 추상적 인 클래스와 컴포지션을 사용하여 원하는 결과를 얻는 많은 다른 디자인 패턴 중 하나입니다.


이 모든 것을 원근법으로 가져올 수학 기회를 주자.


4 개의 커피 블렌드와 10 개의 부가 기능을 가져옵니다. 우리가 한 종류의 커피에 대한 모든 부가 기능의 각기 다른 조합에 대한 하위 클래스 생성을 고집한다면. 그거야.


(10–1)² = 9² = 81 subclasses 


하나의 애드온과 같은 유형의 다른 애드온을 결합 할 수 없기 때문에 10에서 1을 뺍니다. 설탕이 들어있는 설탕은 바보처럼 들립니다. 그리고 그것은 단지 하나의 커피 혼합을 위한 것입니다. 81에 4를 곱하면 무려 324 개의 하위 클래스가 생성됩니다! 모든 코딩에 대해 이야기하십시오 ...


그러나 데코레이터 패턴을 사용하면 이 시나리오에서는 16 개의 클래스만 필요합니다. 내기 할래?


decorator-class-diagram.png 

Decorator Design Pattern Class diagram 


decorator-coffee-class-diagram.png 

Class diagram according to coffee shop scenario 


위의 클래스 다이어그램에 따라 시나리오를 매핑하면 4 개의 커피 블렌드에 대해 4 개의 클래스가 제공됩니다. 각 추가 기능에 대해 10 개, 추상 구성 요소에 대해 1 개, 추상 데코레이터에 대해 1 개가 추가로 제공됩니다. 만나다! 16! 그 100 달러를 넘겨주세요. ?? (jk. 그러나 주어진다면 그것은 거절 당하지 않을 것입니다 ... 그냥 말하기)