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
김치치즈스마일
세계정복!

,