'프로그래밍'에 해당하는 글 63건

enum 2

프로그래밍/Java 2018. 1. 28. 23:29

저번 enum 1에서는 int enum 패턴의 문제점을 확인하였다. 이번부터는 enum이란 과연 무엇인지 본격적으로 알아보자.

enum이란?

· 열거 자료형(enummerated type)은 고정 개수의 상수들로 값이 구성되는 자료형.

· 자바의 enum 자료형은 완전한 기능을 갖춘 클래스.

· 열거 상수(enumeration constant)별로 하나의 객체를 public static final 필드 형태로 제공하는 것. (클라이언트가 접근할 수 있는 생성자가 없기 때문)

· enum 자료형의 개체 수는 엄격히 통제됨. (싱글턴 패턴을 일반화 한 것)

· enum 자료형은 컴파일 시점 형 안정성(compile-time type safety)을 제공함.

· enum 자료형은 name space가 분리되어 있기 때문에 같은 이름의 상수가 평화롭게 공존할 수 있음.

· 상수를 제공하는 필드가 enum 자료형과 클라이언트 사이에서 격리 계층(layer of insulation) 구실을 하기 때문에 상수를 추가하거나 순서를 변경해도 다시 컴파일할 필요가 없음.

· toString 메서드를 호출하면 인쇄 가능 문자열로 쉽게 변환이 가능.

· 임의의 메서드나 필드도 추가 가능.

public enum Apple {
	FUJI, PIPPIN, GRANNY_SMITH
}

public enum Orange {
	NAVEL, TEMPLE, BLOOD
}

※ enum의 간단한 예

 

풍부한 enum 자료형을 만드는 법

· enum 상수에 데이터를 넣으려면 객체 필드(instance field)를 선언하고 생성자를 통해 받은 데이터를 그 필드에 저장하면 됨.

public enum Planet {
	MERCURY (3.302e+23, 2.439e6),
	VENUS (4.869e+24, 6.052e6),
	EARTH (5.975e+24, 6.378e6),
	MARS (6.419e+23, 3.393e6),
                JUPITER (1.899e+27, 7.149e7),
	SATURN (5.685e+26, 6.027e7),
	URANUS (8.683e+25, 2.556e7),
	NEPTUNE (1.024e+26, 2.477e7);
	
	private final double mass; // 킬로그램 단위
	private final double radius; // 미터 단위
	private final double surfaceGravity; // m / s^2
	
	private static final double G = 6.67300E-11;
	
	Planet(double mass, double radius) {
		this.mass = mass;
		this.radius = radius;
		surfaceGravity = G * mass / (radius * radius);
	}
	
	public double mass() {
		return mass;
	}
	
	public double radius() {
		return radius;
	}
	
	public double surfaceGravity() {
		return surfaceGravity;
	}
	
	public double surfaceWeight(double mass) {
		return mass * surfaceGravity; // F = ma
	}
}

public class WeightTable {
	public static void main(String[] args) {	
		Double earthWeight = 175d;
		Double mass = earthWeight / Planet.EARTH.surfaceGravity();
		
		for(Planet p : Planet.values()) {
			System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
		}
	}
}

※ 풍부한 enum 자료형의 예

 

 

[참고] Effective Java

'프로그래밍 > Java' 카테고리의 다른 글

String.format  (0) 2020.01.25
enum 1  (0) 2018.01.02
쓰레드(Thread) 3  (0) 2017.11.20
쓰레드(Thread) 2  (0) 2017.11.04
쓰레드(Thread) 1  (0) 2017.11.03

WRITTEN BY
김치치즈스마일
세계정복!

,

enum 1

프로그래밍/Java 2018. 1. 2. 23:54

사실 평소 개발하면서 enum 자료형을 거의 써보지 않았다. 단순히 int형의 상수들을 가지고 사용하던 것이 익숙했기 때문에 특별히 enum 자료형을 왜 써야하는지 몰랐었다.

하지만 Effective Java를 읽다보니 이러한 int enum 패턴이 굉장히 단점이 많다는 사실을 알게되었다.

 

public static final int APPLE_FUJI = 0;
public static final int APPLE_PITPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

※ int를 사용한 int enum 패턴의 모습

 

int enum 패턴의 단점

· 위의 코드를 보면 사과 관련 상수명이라서 APPLE_이라는 접두어를 붙여서 사용하였다. 이런 접두어는 자바가 int enum 그룹별로 별도의 name space를 제공하지 않기 때문에 사용.

· int enum 상수는 컴파일 시점 상수이기 때문에 상수를 사용하는 클라이언트 코드와 함께 컴파일 됨. 따라서 상수의 int 값이 변경되면 클라이언트도 다시 컴파일해야 함.

· int enum 상수는 인쇄 가능한 문자열로 변환하기도 쉽지 않음. 이런 상수를 출력하거나 디버거로 확인해보면 숫자만 보이기 때문에 크게 도움이 되지 않음. 또한 int enum 상수를 순차적으로 이용하거나, int enum 그룹의 크기를 알아낼 좋은 방법도 없음.

 

이와 같은 단점이 있기 때문에 int enum 패턴은 좋지 않은 방법이다. 그렇다면 이런 int enum 패턴 대신 사용할 enum 자료형은 어떤 것인지 다음 enum 2에서 부터 알아보자.

 

 

[출처] Effective Java

'프로그래밍 > Java' 카테고리의 다른 글

String.format  (0) 2020.01.25
enum 2  (3) 2018.01.28
쓰레드(Thread) 3  (0) 2017.11.20
쓰레드(Thread) 2  (0) 2017.11.04
쓰레드(Thread) 1  (0) 2017.11.03

WRITTEN BY
김치치즈스마일
세계정복!

,

흔히 디자인 패턴을 적용해서 개발하면서 가장 많이 쓰고 있는 패턴이 있다면 싱글턴 패턴일 것이다. (물론 개인적인 기준일 수 있지만)

그만큼 자주 사용하지만 정확히 싱글턴 패턴이란 무엇인지, 왜 사용하는지 설명하려면 어려울 수 있다.

그래서 이번에는 싱글턴 패턴에 대해서 알아보자.

 

싱글턴 패턴이란?

· 오직 한 개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공하는 패턴.

※ 단일체 패턴이라고도 불림.

 

· 클래스 자신이 자기의 유일한 인스턴스로 접근하는 방법을 자체적으로 관리하는 것. 이 클래스는 또 다른 인스턴스가 생성되지 않도록 할 수 있고, 클래스 자신이 그 인스턴스에 대한 접근 방법을 제공할 수 있음.

 

언제 싱글턴 패턴을 사용해야 할까?

· 클래스의 인스턴스가 오직 하나여야 함을 보장하고, 잘 정의된 접근점(Access Point)으로 모든 사용자가 접근할 수 있도록 해야 할 때.

· 유일한 인스턴스가 서브클래싱으로 확장되어야 하며, 사용자는 코드의 수정없이 확장된 서브 클래스의 인스턴스를 사용할 수 있어야 할 때.

 

구조

· Singleton : Instance() 연산을 정의하여, 유일한 인스턴스로 접근할 수 있도록 함. Instance() 연산은 유일한 인스턴스를 생성하는 책임을 맡음.

 

싱글턴 패턴의 장점

· Singleton 클래스 자체가 인스턴스를 캡슐화하기 때문에, 이 클래스에서 사용자가 언제, 어떻게 이 인스턴스에 접근할 수 있는지 제어할 수 있음.

· name space를 좁힘. 즉, 전역 변수를 정의하여 발생하는 디버깅의 어려움 등 문제를 없앰.

· 연산 및 표현의 정제를 허용함.

· 인스턴스의 개수를 변경하기가 자유로움.

· 클래스 연산을 사용하는 것보다 훨씬 유연한 방법.

 

싱글턴 패턴의 종류

· Eager Initialization

public class EagerInitialization {
	private static EagerInitialization instance = new EagerInitialization();
	
	private EagerInitialization () {
		
	}
		
	public static EagerInitialization getInstance () {
		return instance;
	}
}

가장 기본적인 싱글턴 패턴 방법. 전역 변수로 인스턴스를 만드는데 private static을 이용.

· Static Block Initialization

public class StaticBlockInitalization {
	private static StaticBlockInitalization instance;
	
	private StaticBlockInitalization () {
		
	}
	
	static {
		try {
			instance = new StaticBlockInitalization();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static StaticBlockInitalization getInstance () {
		return instance;
	}	
}

static 초기화 블럭을 이용하여 클래스가 로딩 될 때, 최초 한번 실행되며 이때 인스턴스를 생성. 인스턴스가 사용되는 시점에 생성 되는 것이 아님

· Lazy Initialization

public class LazyInitialization {
	private static LazyInitialization instance;
	
	private LazyInitialization () {
		
	}
	
	public static LazyInitialization getInstance () {
		if ( instance == null ) {
			instance = new LazyInitialization();
		}
		
		return instance;
	}
}

기본적으로 본인이 가장 많이 사용하는 방법. getInstance()에서 인스턴스가 없을 경우에만 새로 인스턴스를 생성해주는 방법. 하지만 multi thread의 경우 인스턴스가 두번 생길 위험이 존재함.

· Thread Safe Initialization

public class ThreadSafeInitalization {
	private static ThreadSafeInitalization instance;
	
	private ThreadSafeInitalization () {
		
	}
	
	public static synchronized ThreadSafeInitalization getInstance () {
		if (instance == null) {
			instance = new ThreadSafeInitalization();
		}
		
		return instance;
	}
}

위에 있는 Lazy Initialization의 multi thread 문제를 해결하기 위해 synchronized(동기화)를 사용하여 구현함. 높은 cost 비용으로 프로그램 전반에 성능 저하가 일어날 수 있음.

· Initialization on Demand Holder Idiom

public class InitializationOnDemandHolderIdiom {
	private InitializationOnDemandHolderIdiom () {
		
	}
	
	private static class Singleton {
		private static final InitializationOnDemandHolderIdiom instance = new InitializationOnDemandHolderIdiom();
	}
	
	public static InitializationOnDemandHolderIdiom getInstance () {
		return Singleton.instance;
	}
}

Bill pugh라는 컴퓨터 과학 연구원이 기존의 싱글턴 패턴의 문제점들을 해결하기 위해서 만든 새로운 싱글턴 패턴. 이것은 jvm의 class loader 매커니즘과 class load 시점을 이용하여 인스턴스를 생성시킴으로 thread간의 동기화 문제를 해결함. (Bill pugh가 만들었다 해서 Bill pugh Singleton이라고 부르기도 함)

· Enum Initialization

public enum EnumInitialization {
	INSTANCE;
		
	public static EnumInitialization getInstance() {
		return INSTANCE;
	}
}

Joshua Bolch의 Effective Java라는 책에서 소개된 enum 싱글턴 방법.

- enum은 인스턴스가 생성될 때, multi thread로부터 안전함

- 단 한번의 인스턴스 생성을 보장함.

- 또한 enum value는 자바 프로그램 전역에서 접근이 가능함.

따라서 위와 같은 이유로 enum을 싱글턴 패턴으로 사용될 수 있음.

 

※ 종류와 관련된 더욱 자세한 내용은 아래 [참고]에 나와있는 블로그를 봐주시면 되겠습니다.

싱글턴 패턴의 예

· Session

· Cache

· Logger

 

[참고] https://blog.seotory.com/post/2016/03/java-singleton-pattern

[참고] GoF의 디자인 패턴


WRITTEN BY
김치치즈스마일
세계정복!

,

앞서서 팩토리 메서드 패턴을 알아보았았다. 이번에는 추상 팩토리 패턴에 대해서 알아보도록 하자.

 

추상 팩토리 패턴이란?

· 상세화된 서브클래스를 정의하지 않고도 서로 관련성이 있거나 독립적인 여러 객체의 군을 생성하기 위한 인터페이스를 제공하는 패턴.

※ 키트(Kit) 패턴이라고도 불림.

 

 

우리가 편의점에서 자주 사먹는 삼각 김밥을 예를 들어보겠다. 삼각 김밥은 삼각 김밥을 만드는 어느 공장에서 만들어져서 편의점으로 운반되었을 것이다.

하지만 그 삼각 김밥 안에 들어가는 재료인 참치라던가 고기, 야채들은 각각의 참치 공장, 고기 공장, 야채 공장에서 다 손질되어서 삼각 김밥을 만드는 공장으로 운반되었을 것이다.

이와 같은 모양을 추상 팩토리 패턴에 대입해서 생각해보면 될 것 같다.

 

언제 추상 팩토리를 사용해야 할까?

· 객체가 생성되거나 구성 · 표현되는 방식과 무관하게 시스템을 독립적으로 만들고자 할 때.

· 여러 제품군 중 하나를 선택해서 시스템을 설정해야 하고 한번 구성한 제품을 다른 것으로 대체할 수 있을 때.

· 관련된 제품 객체들이 함께 사용되도록 설계되었고, 이 부분에 대한 제약이 외부에도 지켜지도록 하고 싶을 때.

· 제품에 대한 클래스 라이브러리를 제공하고, 그들의 구현이 아닌 인터페이스를 노출시키고 싶을 때.

 

구조

· AbstractFactory : 개념적 제품에 대한 객체를 생성하는 연산으로 인터페이스를 정의함.

· ConcreteFactory : 구체적인 제품에 대한 객체를 생성하는 연산을 구현함.

· AbstractProduct : 개념적 제품 객체에 대한 인터페이스를 정의함.

· ConcreteProduct : 구체적으로 팩토리가 생성할 객체를 정의하고, AbstractProduct가 정의하는 인터페이스를 구현함.

· Client : AbsctractFactory와 AbstractProduct 클래스에 선언된 인터페이스를 사용함.

 

추상 팩토리 패턴의 장점

· 구체적인 클래스가 사용자에게 분리되어 사용자 코드에는 나타나지 않음.

· 제품군을 쉽게 대체할 수 있도록 함.

· 제품 사이의 일관성을 증진시킴.

 

[프로그래밍/디자인 패턴] - 팩토리 메서드(Factory Method) 패턴

 

 

[참고] GoF의 디자인 패턴


WRITTEN BY
김치치즈스마일
세계정복!

,

흔히 팩토리하면 우리는 무언가 기계로 물건들을 계속해서 제조하는 그런 공장을 떠올릴 것이다.

그렇다면 팩토리 메서드 패턴은 우리가 알고있는 공장과 어떤 연관 관계가 있는 것일까?

이제부터 팩토리 메서드 패턴에 대해서 알아보자.

 

팩토리 메서드 패턴이란?

· 객체를 생성하기 위해 인터페이스를 정의하지만, 어떤 클래스의 인스턴스를 생성할지에 대한 결정은 서브클래스가 내리도록 하는 패턴.

※ 가상 생성자(Virtual Constructor) 패턴이라고도 불림.

 

· 서브클래스 중 어느 것을 생성해야 하는지에 대한 정보를 캡슐화하고, 클라이언트 코드와 서브클래스의 코드를 뗴어냄.

· 서브클래스에서 어떤 클래스를 생성할지 오버라이드 한 메서드가 바로 팩토리 메서드.

· 객체를 제조하는 방법을 알기 때문에 팩토리 메서드라고 불림.

 

언제 팩토리 메서드 패턴을 사용해야 할까?

· 어떤 클래스가 자신이 생성해야 하는 객체의 클래스를 예측할 수 없을 때.

· 생성할 객체를 기술하는 책임을 자신의 서브클래스가 지정했으면 할 때.

· 객체 생서으이 책임을 몇 개의 보조 서브클래스 가운데 하나에게 위임하고, 어떤 서브클래스가 위임자인지에 대한 정보를 국소화 시키고 싶을 때.

 

구조

· Product : 팩토리 메서드가 생성하는 객체의 인터페이스를 정의함.

· ConcreteProduct : Product 클래스에 정의된 인터페이스를 실제로 구현함.

· Creator : Product 타입의 객체를 반환한느 팩토리 메서드를 선언함. Creator 클래스는 팩토리 메서드를 기본적으로 구현하는데, 이 구현에서는 ConcreteProduct 객체를 반환함. 또한 Product 객체의 생성을 위해 팩토리 메서드를 호출함.

· ConcreteCreator : 팩토리 메서드를 재정의하여 ConcreteProduct의 인스턴스를 반환함.

 

팩토리 메서드 패턴의 장점

· 팩토리 메서드 패턴은 응용프로그램에 국한된 클래스가 코드에 종속되지 않도록 해줌.

· 서브클래스에 대한 훅(hook) 메서드를 제공.

· 병렬적인 클래스 계통을 연결하는 역할을 담당.

 

[프로그래밍/디자인 패턴] - 추상 팩토리(Abstract Factory) 패턴

 

 

[참고] GoF의 디자인 패턴


WRITTEN BY
김치치즈스마일
세계정복!

,

우리는 무언가 추가하여 꾸밀 때 데코레이션한다는 표현을 많이 쓴다. 그렇다면 데코레이터 패턴도 무언가를 추가해서 꾸미는 패턴일까?

데코레이터 패턴이 무엇인지 한번 알아보자.

 

데코레이터 패턴이란?

· 객체에 동적으로 새로운 책임을 추가할 수 있게 하는 패턴. (서브클래스를 생성하는 것[상속]보다 융통성 있는 방법을 제공)

※ 장식자 패턴, 랩퍼(Wrapper) 패턴이라고도 부름.

 

· 무엇인가를 감싸는 객체를 데코레이터(Decorator)라고 부름. 데코레이터는 자신이 둘러싼 요소, 구성요소가 갖는 인터페이스를 자신도 동일하게 제공하므로, 데코레이터의 존재는 이를 사용하는 사용자에게 감춰짐.

즉, 데코레이터는 자신이 둘러싼 구성요소로 전달되는 요청을 중간에 가로채서 해당 구성요소에 전달해줌.

그렇기 때문에 이 전달 과정의 앞뒤에 다른 작업을 추가로 할 수 있음.

 

 

데코레이터 패턴이 무엇인지 알아보았지만 아직 와닿지는 않을 것이며, 언제 사용해야 할지 잘 모를 것이다. 그렇다면 이런 데코레이터 패턴은 언제 사용해야 좋을지 알아보자.

 

언제 데코레이터 패턴은 사용해야 할까?

· 동적으로 또한 투명하게, 다시 말해 다른 객체에 영향을 주지 않고 개개의 객체에 새로운 책임을 추가하기 위해 사용.

· 제거될 수 있는 책임에 대해 사용.

· 실제 상속으로 서브클래스를 계속 만드는 방법이 실질적이지 못할 때 사용. (너무 많은 수의 독립된 확장이 가능할 때 모든 조합을 지원하기 위해 이를 상속으로 해결하면 클래스 수가 폭발적으로 많아지게 됨)

 

구조


 

· Component : 동적으로 추가할 서비스를 가질 가능성이 있는 객체들에 대한 인터페이스.

· ConcreteComponent : 추가적인 서비스가 실제로 정의되어야 할 필요가 있는 객체.

· Decorator : Component 객체에 대한 참조자를 관리하면서 Component에 정의된 인터페이스를 만족하도록 인터페이스를 정의.

· ConcreteDecorator : Component에 새롭게 추가할 서비스를 실제로 구현하는 클래스.

 

데코레이터 패턴의 장점

· 단순한 상속보다 설계의 융통성을 더 많이 증대시킬 수 있음. (상속은 정적으로 새로운 클래스를 추가해야만 추가적인 행동을 정의할 수 있는 방법)

· 클래스 계통의 상부측 클래스에 많은 기능이 누적되는 상황을 피할 수 있음. *필요한 비용만 그때 지불해라!

 

데코레이터 패턴의 예

· 스트림(Stream)

 

 

[참고] GoF의 디자인 패턴


WRITTEN BY
김치치즈스마일
세계정복!

,

 

옵저버 패턴이란 무엇일까? 옵저버하면 스타크래프트에서 나오는 프로토스 정찰 비행선이 생각난다.

그 비행선처럼 무언가 감지하여 우리가 알 수 있게 해주는 그런 패턴일까??? 옵저버 패턴이 무엇인지 알아보자.

 

옵저버 패턴이란?

· 객체 사이에 일 대 다의 의존 관계를 정의해 두어, 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 만드는 패턴.

※ 감시자 패턴, 종속자(Dependent) 패턴, 게시-구독(Publish-Subscribe) 패턴이라고도 불림.

 

· 옵저버 패턴에서 가장 중요한 객체는 주체(Subject)감시자(Observer)

- 주체는 독립된 여러 개의 감시가 있을 수 있음.

- 모든 감시자는 주체의 상태 변화가 있을 때마다 이 변화를 통보 받음.

- 각 감시자는 주체의 상태와 자신의 상태를 동기화시키기 위해 주체의 상태를 알아봄.

※ 위와 같은 상호작용을 게시-구독 관계라고 함. 주체는 상태 변경에 대한 통보를 하는 것이므로 누가 감시자인지 모른 채 통보를 발송, 불특정 다수의 감시자가 이 통보를 수신하기 위해서 구독을 신청하는 것.

 

 

이제는 옵저버 패턴이 무엇인지 어느정도 의미를 알았지만 과연 이 패턴을 언제 사용해야 할지 막막할것이다. 언제 옵저버 패턴을 사용해야 할지 간략하게 알아보자.

언제 옵저버 패턴을 사용해야 할까?

· 어떤 추상 개념이 두 가지 양상을 갖고 하나가 다른 하나에 종속적일 때.

· 한 객체에 가해진 변경으로 다른 객체를 변경해야 하고, 프로그래머들은 얼마나 많은 객체들이 변경되어야 하는지 몰라도 될 때.

· 어떤 객체가 다른 객체에 자신의 변화를 통보할 수 있는데, 그 변화에 관심있어 하는 객체들이 누구인지에 대한 가정 없이도 그러한 통보가 될 때.

 

구조

 

· Subject : 감시자들을 알고 있는 주체. 임의 개수의 감시자 객체는 주체를 감시할 수 있음. 주체는 감시자 객체를 붙이거나 떼는 데 필요한 인터페이스를 제공함.

· Observer : 주체에 생긴 변화에 관심 있는 객체를 갱신하는데 필요한 인터페이스를 정의함. 이로써 주체의 변경에 따라 변화되어야 하는 객체드르이 일관성을 유지할 수 있음.

· ConcreteSubject : ConcreteObserver 객체에게 알려주어야 하는 상태를 저장함. 또한 이 상태가 변경될 때 감시자에게 변경을 통보함.

· ConcreteObserver : ConcreteSubject 객체에 대한 참조자를 관리함. 주체의 상태와 일관성을 유지해야 하는 상태를 저장함. 주체의 상태와 감시자의 상태를 일관되게 유지하는 데 갱신 인터페이스를 구현.

 

옵저버 패턴의 장점

· Subject와 Observer 클래스 간에는 추상적이며 최소한의 결합도만이 존재함.

· 브로드캐스트(broadcast) 방식의 교류를 가능하게 함.

· 예측하지 못한 정보를 갱신함.

 

옵저버 패턴의 예

· MCV 모델 (모델 == Subject / 뷰 == Observer)

 

 

[참고] GoF의 디자인 패턴


WRITTEN BY
김치치즈스마일
세계정복!

,

 

 

객체지향 소프트웨어를 설계하는 것은 쉬운 일이 아니다. 게다가, 재사용할 수 있는 객체지향 소프트웨어를 만드는 것은 더욱 힘든 일이다.

이처럼 힘든 일인 올바른 객체지향 소프트웨어를 만드는 것을 보다 쉽게 할 수 있게끔 도와주는 것이 있는데, 이것이 바로 디자인 패턴이다. 지금부터 디자인 패턴이 무엇인지 알아보자.

 

"각 디자인 패턴은 기존 환경 내에서 반복적으로 일어나는 문제들을 설명한 후, 그 문제들에 대한 해법의 핵심을 설명해 줍니다. 똑같은 방법으로 두 번 하지 않고 이 해법을 100만 번 이상 재사용할 수 있도록 말이죠."

- 건축가이자 패턴의 아버지, 크리스토퍼 알렉산더 -

 

디자인 패턴이란?

· 특정한 전후 관계에서 일반적 설계 문제를 해결하기 위해 상호교류하는 수정 가능한 객체와 클래스들에 대한 설명.

· 설계에서 얻은 세세한 경험들을 다른 사람이 응용하기 좋도록 자세히 기록한 것.

 

패턴에 들어가는 네 가지 요소

· 패턴 이름(Pattern name)

패턴 이름은 한두 단어로 설계 문제와 해법을 서술함. 패턴의 의도를 표현하고 설계에 대한 생각을 쉽게 함.

 

· 문제(Problem)

문제는 언제 패턴을 사용하는 가를 서술하며 해결할 문제와 그 배경을 설명함.

 

· 해법(Solution)

해법은 설계를 구성하는 요소들과 그 요소들 간의 관계, 책임 그리고 협력 관계를 서술함.

구체적인 부분을 제시하지 않고 문제에 대한 추상적인 설명을 제공하고 문제를 해결하기 위해서 클래스나 객체들의 나열 방법을 제공함.

 

· 결과(Consequence)

결과는 디자인 패턴을 적용해서 얻는 결과와 장단점을 서술함. 소프트웨어에서의 결과란 가끔 시간이나 공간 사이의 균형일 수도 있음. 즉, 시간을 중요한 요소로 볼 것인지 저장 공간의 효율을 중요한 요소로 볼 것인지에 따라 다른 설계 방법을 선택해야 함.

 

패턴 분류 기준

· 목적(purpose)

· 범위(scope)

 

목적

패턴이 무엇을 하는지 정의 하는 것.

크게 생성, 구조, 행동 중의 하나의 목적을 가짐.

 

· 생성

객체의 생성 과정에 관여하는 패턴.

· 구조

클래스나 객체의 합성에 관한 패턴.

· 행동

클래스나 객체들이 상호작용하는 방법과 책임을 분산하는 방법을 정의하는 패턴.

 

범위

패턴을 주로 클래스에 적용하는지 아니면 객체에 적용하는지를 구분하는 것.

크게 클래스 패턴과 객체 패턴으로 구분.

 

· 클래스 패턴

클래스와 서브클래스 간의 관련성을 다루는 패턴.

관련성은 주로 상속이며 컴파일 타임에 정적으로 결정

 

· 객체 패턴

객체 관련성을 다루는 패턴.

런타임에 변경할 수 있으며 더 동적인 성격을 가짐.

 

 

[참고] GoF의 디자인 패턴

 

 

 


WRITTEN BY
김치치즈스마일
세계정복!

,

앞선 쓰레드1쓰레드2를 통해서 쓰레드에 관한 내용들을 알아보았는데 이제 쓰레드에 관한 정리도 끝나간다. (앞에 내용을 보지 못하신 분들은 링크를 타고 보실 것을 권함)

이번에는 쓰레드를 사용하면서 동기화란 어떤 것이면 어떻게 사용하는지와 어떻게하면 동기화의 효율을 높일 수 있는지 알아보자.

 

쓰레드의 동기화란?

내가 컴퓨터로 몇시간동안 문서 작업을 하다가 잠시 자리를 비운 사이에 다른 사람이 문서를 만든다고 건드려서 내 작업이 날아가면 어떻게 될까??? (생각만 해도 끔찍...ㅠㅠ!!!)

이럴 때는 문서 작업이 다 끝날 때까지 다른 사람이 컴퓨터를 사용할 수 없게 비밀번호를 설정해서 잠금 상태(lock)로 해놓으면 될 것 같다.

이처럼, 데이터에 lock을 걸어서 먼저 작업 중이던 쓰레드가 작업을 완전히 마칠 때까지는 다른 쓰레드에게 제어권이 넘어가더라도 데이터가 변경되지 않도록 보호함으로써 동기화를 시킬 수 있다.

 

synchronized를 이용한 동기화

자바에서는 키워드 synchronized를 이용해 공유 데이터에 lock을 걸어서 동기화를 가능하게 함.

이때, synchronized는 두 가지 방법으로 사용 됨.

 

· 특정한 객체에 lock을 걸고자 할 때

synchronized(객체의 참조변수) {
	
}

synchronized 블록의 경우, 지정된 객체는 synchronized 블럭의 시작부터 lock이 걸렸다가 블록이 끝나면 lock이 풀림.

이 블록을 수행하는 동안은 지정된 객체에 lock이 걸려서 다른 쓰레드가 이 객체에 접근할 수 없게 됨.

 

· 메서드에 lock을 걸고자 할 때

public synchronized void cal() {
	
}

synchronized 메서드의 경우, 한 쓰레드가 synchronized 메서드를 호출해서 수행하고 있으면 메서드가 종료될 때까지 다른 쓰레드가 이 메서드를 호출할 수 없음.

 

교착상태(dead lock)에 빠질 수 있기때문에 가능하면 메서드에 synchronized를 사용하는 메서드 단위의 동기화를 권장.

 

 

 

쓰레드를 동기화 할때, 한 쓰레드가 객체에 lock을 걸고 어떤 조건이 만족될 때까지 기다려야 하는 경우가 생길 수 있다. 이럴 때, 이 쓰레드를 그대로 놔두면 이 객체를 사용하려는 다른 쓰레드들은 lock이 풀릴 때까지 같이 기다려야만 하는 상황이 발생한다.

이런 비효율을 개선하기 위해서 wait()와 notify() 또는 notifyAll()을 사용하여 동기화의 효율을 높여준다.

wait()

한 쓰레드가 객체에 lock을 걸고 오래 기다리는 대신 wait()을 호출해서 다른 쓰레드에게 제어권을 넘겨주고 대기 상태로 기다림.

Thread 클래스가 아닌 Object 클래스에서 정의된 메서드로 모든 객체에서 호출이 가능.

동기화 블록 내에서만 사용 가능.

 

notify()

대기 상태로 기다리는 쓰레드를 다른 쓰레드에 의해서 notify()가 호출되면 다시 실행상태로 만듬.

Thread 클래스가 아닌 Object 클래스에서 정의된 메서드로 모든 객체에서 호출이 가능.

동기화 블록 내에서만 사용 가능.

 

notify()와 notifyAll()의 차이점

notify()는 waiting pool에 있는 쓰레드 중에서 하나만 깨우고 notifyAll()은 모든 쓰레드를 깨움. 하지만 어차피 한 번에 하나의 쓰레드만 사용 가능하기 때문에 별 차이는 없음.

 

※ notify()를 사용할 경우 어떤 쓰레드가 깨워지게 될지는 알 수 없어서 특정 쓰레드가 오랫동안 waiting pool에 머물 수 있기 때문에 다시 객체의 waiting pool에 들어가게 되더라도 notifyAll()을 이용해서 모든 쓰레드를 깨워놓고 JVM의 쓰레드 스케줄링에 의해서 처리되도록 하는 것이 안전함.

 

 

2017/11/03 - [프로그래밍/Java] - 쓰레드(Thread) 1

2017/11/04 - [프로그래밍/Java] - 쓰레드(Thread) 2

 

 

 

 

'프로그래밍 > Java' 카테고리의 다른 글

enum 2  (3) 2018.01.28
enum 1  (0) 2018.01.02
쓰레드(Thread) 2  (0) 2017.11.04
쓰레드(Thread) 1  (0) 2017.11.03
컬렉션 프레임워크(Collection Framework)란?  (0) 2017.09.01

WRITTEN BY
김치치즈스마일
세계정복!

,

앞서서 쓰레드에 관한 기본적인 내용들을 알아보았다.

이번에는 쓰레드의 세부적인 것을 알아보도록 하자.

 

 

쓰레드의 우선순위

· 쓰레드는 우선순위(priority)라는 것을 가지고 있어서 우선순위의 값에 따라 쓰레드가 얻는 시간을 다르게 줄 수 있음.

· 쓰레드가 가질 수 있는 우선 순위의 범위는 1에서 10까지 이며 높을수록 우선순위가 높은 것. (우선 순위의 높고 낮음은 절대적인 것이 아닌 상대적인 것)

· 쓰레드의 우선순위는 쓰레드를 생성한 쓰레드로부터 상속 받는 것. (main메서드를 수행하는 쓰레드는 우선순위가 5이므로 main 메서드 내에서 생성하는 쓰레드는 자동적으로 우선순위가 5가 됨)

 

void setPriority(int newPriority); // 쓰레드의 우선순위를 지정한 값으로 변경
int getPriority(); // 쓰레드의 우선순위를 반환
		
public static final int MAX_PRIORITY = 10; // 최대 우선순위
public static final int MIN_PRIORITY = 1; // 최소 우선순위
public static final int NORM_PRIORITY = 5; // 보통 우선순위

 

쓰레드의 스케줄링과 관련된 메서드

생성자 / 메서드 

설명 

void interrupt()

sleep()이나 join()에 의해 일시정지인 쓰레드를 실행대기상태로 만듬

해당 쓰레드에서는 interruptedException일 발생하여 일시정지상태를 벗어나게 됨

void join()

void join(long millis)

void join(long millis, ont nanos)

지정된 시간동안 쓰레드가 실행되도록 함

지정된 시간이 지나거나 작업이 종료되면 join()을 호출한 쓰레드로 다시 돌아가 실행을 계속 함 

void resume() 

suspend()에 의해 일시정지해 있는 쓰레드를 실행대기상태로 만듬

교착상태에 빠지기 쉽기 때문에 deprecated됨

static void sleep(long millis)

static void sleep(long millis, int nanos)

지정된 시간동안 쓰레드를 일시정지시킴

지정한 시간이 지나면 자동적으로 다시 실행대기 상태가 됨 

void stop() 

쓰레ㅐ드를 즉시 종료 시킴

교착상태에 빠지기 쉽기 때문에 deprecated됨

void suspend() 

쓰레드를 일시정지시킴

resume()을 호출하면 다시 실행대기상태가 됨

교착상태에 빠지기 쉽기 때문에 deprecated됨

static void yield() 

실행 중에 다른 쓰레드에게 양보하고 실행대기상태가 됨 

 

쓰레드의 상태

상태 

설명 

NEW 

쓰레드가 생성되고 아직 start()가 호출되지 않은 상태

RUNNABLE 

실행 중 또는 실행 가능한 상태 

BLOCKED 

동기화 블럭에 의해서 일시정지된 상태 (lock이 풀릴 때까지 기다리는 상태)

WAITING, TIMED_WAITING 

쓰레드의 작업이 종료되지는 않았지만 실행가능하지 않은(unrunnable) 일시정지 상태

TIMED_WAITING은 일시정지시간이 지정된 경우를 의미

TERMINATED 

쓰레드의 작업이 종료된 상태

 

 

[참고] 자바의 정석

 

 

2017/11/03 - [프로그래밍/Java] - 쓰레드(Thread) 1

 

'프로그래밍 > Java' 카테고리의 다른 글

enum 1  (0) 2018.01.02
쓰레드(Thread) 3  (0) 2017.11.20
쓰레드(Thread) 1  (0) 2017.11.03
컬렉션 프레임워크(Collection Framework)란?  (0) 2017.09.01
throw와 throws 비교  (0) 2017.08.28

WRITTEN BY
김치치즈스마일
세계정복!

,