[Effective Java] Item 01. ์์ฑ์ ๋์ ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ๊ณ ๋ คํ๋ผ
์ด ๊ธ์ ๊ณต๋ถ๋ฅผ ํ๋ฉด์ ์๊ฒ ๋ ๋ด์ฉ๋ค์ ๊ธฐ๋กํ๋ ๊ธ ์ ๋๋ค. ์ค๋ฅ๋ ๊ณ ์ณ์ผ ํ ์ฌํญ๋ค์ด ์๋ค๋ฉด ์ง์ ๋ถํ๋๋ฆฝ๋๋ค!
๋ง์ง๋ง ์์ : 2024.05.27
โ 1. ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋ (static factory method)๋?
ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ ์ ์ ๋ฉ์๋(static method)๋ฅผ ๋งํ๋ค.
๋ํ์ ์ผ๋ก java์ Wrapper class๋ค์ .valueOf()
๋ผ๋ ๋ฉ์๋๋ค์ ์ ๊ณตํ๊ณ ์๋ค.Boolean.valueOf()
, String.valueOf()
์ด ๊ทธ ๋ํ์ ์ธ ์์์ด๋ฉฐ, ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด Wrapper class์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค.
โ 2. ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋์ ์ฅ์
1๏ธโฃ ์ด๋ฆ์ ๊ฐ์ง ์ ์๋ค.
์ด๋ค ํ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์ํฉ์ ๋ฐ๋ผ ์ ๋ฌ๋๋ ๋งค๊ฐ๋ณ์๊ฐ ๋ค๋ฅด๋ค๋ฉด, ํ๋์ ์์ฑ์๋ก๋ ์ด๋ฅผ ์ถฉ๋ถํ ํํํ๊ธฐ ํ๋ค ๊ฒ์ด๋ค.
์๋ฅผ ๋ค์ด User
์ด๋ผ๋ ๊ฐ์ฒด๊ฐ ์ ๋ฌ๋๋ ๋งค๊ฐ๋ณ์์ ๋ฐ๋ผ ์ค์ ๋๋ ํ๋์ ๊ฐ์ด ๋ค๋ฅด๋ค๊ณ ๊ฐ์ ํ์.
์์ฑ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ java์์๋ public User(String name){}
public User(String nickname) {}
๊ณผ ๊ฐ์ด ์์ฑ์๋ฅผ ์ค๋ณต์ผ๋ก ๋ง๋ค ์ ์๊ธฐ ๋๋ฌธ์, ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๊ฐ ๋ง์ ๋์์ด ๋ ์ ์๋ค.
public class User {
private String name;
private String nickname;
public static User withName (String name) {
User user = new User();
user.name = name;
return user;
}
public static User withNickname (String nickname) {
User user = new User();
user.nickname = nickname;
return user;
}
}
2๏ธโฃ ํธ์ถ ๋ ๋๋ง๋ค ์ธ์คํด์ค๋ฅผ ์๋ก ์์ฑํ์ง ์์๋ ๋๋ค.
โจ ์ฑ๋ฅ์ ๋์ด์ฌ๋ฆด ์ ์๋ค.
๋ถ๋ณ ํด๋์ค(Immutable class; item 17)์ ๊ฒฝ์ฐ ์ธ์คํด์ค๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ฑฐ๋, ์์ฑํ ์ธ์คํด์ค๋ฅผ cachingํ์ฌ ์ฌํ์ฉํ๋ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์๋ค.
ํน์ ํด๋์ค์ ์์ฒญ์ด ์์ฃผ ๋ฐ์ํ๋ ๊ฒฝ์ฐ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ํ์ฉํ๋ค๋ฉด ์ฑ๋ฅ ๋ถ๋ถ์์ ์ด๋์ ๋ณผ ์ ์์ผ๋ฉฐ,
ํนํ ํด๋์ค์ ์์ฑ ๋น์ฉ์ด ํฐ ๊ฒฝ์ฐ ์ฑ๋ฅ์ ๋์ฑ ๋์ด์ฌ๋ฆด ์ ์๋ค.
์ด๋ฌํ ๋ฉด์์ Flyweight pattern
๋ ์ด์ ๋น์ทํ ๊ธฐ๋ฒ์ผ๋ก ๋ณผ ์ ์๋ค.
โจ ์ธ์คํด์ค ํต์ (instance-controlled) ํด๋์ค๋ก ์ฌ์ฉ ๊ฐ๋ฅ
๋ฐ๋ณต๋๋ ์์ฒญ์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด, ํด๋น ํด๋์ค๋ ์ธ์
์ด๋
์ธ์คํด์ค๋ฅผ ์ด์์๊ฒ ํ ์ง ํต์ ํ ์ ์๋ค.
์ด๋ฌํ ํด๋์ค๋ฅผ ์ธ์คํด์ค ํต์ (instance-controlled) ํด๋์ค๋ผ๊ณ ํ๋ค.
๐ค ์ธ์คํด์ค๋ฅผ ํต์ ํ๋ฉด ๋ฌด์์ด ์ข์๊น?
โ ํด๋์ค๋ฅผ ์ฑ๊ธํด(Singleton; item 3)์ผ๋ก ๋ง๋ค ์ ์๋ค.
โ ์ธ์คํด์คํ ๋ถ๊ฐ(noninstantiable; item 4)๋ก ๋ง๋ค ์ ์๋ค.
โ ๋ถ๋ณ ํด๋์ค(immutable class; item 17)์์ ๋์น์ธ ์ธ์คํด์ค๊ฐ ํ๋ ๋ฟ์์ ๋ณด์ฅ ๊ฐ๋ฅ๋ํ ์ธ์คํด์ค ํต์ ๋ Flyweight pattern์ ๋ฒ ์ด์ค๊ฐ ๋๋ค.
3๏ธโฃ ๋ฐํ ํ์ ์ ํ์ ํ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์ ์๋ ๋ฅ๋ ฅ์ด ์๋ค.
โจ ์ด ๋ฅ๋ ฅ์ ํตํด ๋ฐํํ ๊ฐ์ฒด์ ํด๋์ค๋ฅผ ์์ ๋กญ๊ฒ ์ ํํ ์ ์๋
์์ฒญ๋ ์ ์ฐ์ฑ
๊ฐ์ ์ ๊ฐ์ง ์ ์๋ค.
์ด๋ฌํ ๊ฐ์ ์ API๋ฅผ ๋ง๋ค ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
Java 8๋ถํฐ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
์ ๋ฐํ ํ์
์ผ๋ก ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋๋ฐ,
์ด๊ฒ์ด ๋ฐ๋ก ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ ์์ํฌ(item 20)์ ํต์ฌ ๊ธฐ๋ฅ์ด๋ค.
๋ํ์ ์ธ ์๋ก java.util.Collections
๋ฅผ ๋ค ์ ์๋ค.
์๋ฐ ํ๋ ์์ํฌ๋ ์์ ๋ถ๊ฐ(Unmodifiable)๋ ๋๊ธฐํ ๋ฑ์ ๊ธฐ๋ฅ์ ๊ฐ์ง 45๊ฐ์ ์ ํธ๋ฆฌํฐ ๊ตฌํ์ฒด๋ฅผ ์ ๊ณตํ๋ค.
์ด๋ฌํ ๊ตฌํ์ฒด๋ค์ java.util.Collections
์์ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
๋ฅผ ํตํด ์ป์ ์ ์๊ฒ ํ์์ผ๋ฉฐ,
์ด์ฒ๋ผ ๊ตฌํ์ฒด๊ฐ ์๋ ์ธํฐํ์ด์ค์๋ง ์์กดํ๊ฒ ํ์ฌ, ํ๋ก๊ทธ๋๋จธ๋ค์ด API๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์ตํ์ผํ๋ ๊ฐ๋
์ ์์ ๋์ด๋๊ฐ ๋ฎ์์ก๋ค.
๋ํ ํ๋ก๊ทธ๋๋จธ๋ ๊ฐ์ฒด๊ฐ ์ธํฐํ์ด์ค๋๋ก ๋์ํ ๊ฒ์์ ํ์ ํ ์ ์๊ธฐ ๋๋ฌธ์,
public static <T> List<T> unmodifiableList(List<? extends T> list) {
if (list.getClass() == UnmodifiableList.class || list.getClass() == UnmodifiableRandomAccessList.class) {
return (List<T>) list;
}
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
์์ ์ฝ๋๋ Collections
์์ ๊ฐ์ ธ์จ ํ๋์ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋์ด๋ค.
Collections์์๋ ์์ ์ด ๋ถ๊ฐ๋ฅํ ์๋ฃ๊ตฌ์กฐ(List, Set, Map ๋ฑ)๋ฅผ ๋ฐํํด์ฃผ๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ค์ด ์กด์ฌํ๋ค.
์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋์ ๋ฐํ ํ์
์ผ๋ก ์ธํฐํ์ด์ค(List)๋ฅผ ์ฌ์ฉํ ์ ์์๊ธฐ ๋๋ฌธ์, ํ๋ก๊ทธ๋๋จธ๋ Collections.unmodifiableList()
๋ฅผ ํธ์ถํ์ฌ ์์ ์ด ๋ถ๊ฐ๋ฅํ List๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์๋ค.
4๏ธโฃ ์ ๋ ฅ ๋งค๊ฐ๋ณ์์ ๋ฐ๋ผ ๋งค๋ฒ ๋ค๋ฅธ ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์ ์๋ค.
๋ฐํ ํ์ ์ด ํ์ ํ์ (์์๋ฐ์ ์์ ํ์ )์ด๋ผ๋ฉด, ์ด๋ค ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ์๊ด์๋ค.
EnumSet
์ ์๋ก ๋ค์ด๋ณผ ์ ์๋ค.EnumSet
์ public
์์ฑ์ ์์ด ์ค์ง ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ง ์ ๊ณตํ๋๋ฐ, ์์์ ์์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ์ ๋ค๋ฅธ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค.
๋ง์ผ ์์๊ฐ 64๊ฐ ์ดํ๋ผ๋ฉด long ๋ณ์ ํ๋๋ก ๊ด๋ฆฌํ๋ RegularEnumSet
์, 65๊ฐ ์ด์์ด๋ผ๋ฉด long ๋ฐฐ์ด๋ก ๊ด๋ฆฌํ๋ JumboEnumSet
์ ๋ฐํํ๋ค.
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
ํ์ง๋ง ํ๋ก๊ทธ๋๋จธ๋ ์ด๋ฌํ ์ธ๋ถ ๊ตฌํ ์ฌํญ์ ๋ํด ์์ง ์์๋ ๋๋ฉฐ,EnumSet
๋ฅผ ๊ตฌํํ๋ ์
์ฅ์์๋ EnumSet์ ์์ํ ํ์
์ ๋ฐํํ๊ธฐ๋ง ํ๋ฉด ๋๋ฏ๋ก ํ์์ ๋ฐ๋ผ ๋ค๋ฅธ ํ์
์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉฐ ์ฑ๋ฅ ์ ์ด์ ์ ๋
ธ๋ฆด ์ ์๋ค.
5๏ธโฃ ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์์ฑํ๋ ์์ ์๋ ๋ฐํํ ๊ฐ์ฒด์ ํด๋์ค๊ฐ ์กด์ฌํ์ง ์์๋ ๋๋ค.
๋ค์ฏ๋ฒ์งธ ์ด์ ์ ์๋น์ค ์ ๊ณต์ ํ๋ ์์ํฌ(Service Provider Framework)์ ๊ทผ๊ฐ์ด ๋๋ค.
ํ๋ ์์ํฌ๋ ์ ๊ณต์(Provider)๋ ์๋น์ค์ ๊ตฌํ์ฒด๋ฅผ ์ด์ผ๊ธฐํ๋๋ฐ,
ํ๋ ์์ํฌ๋ ์ด ๊ตฌํ์ฒด๋ค์ ์ ๊ณตํ๋ ๊ฒ์ ํต์ (control)ํ๋ฉฐ ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌํ์ฒด๋ก๋ถํฐ ๋ถ๋ฆฌํด์ค๋ค.
๋ํ์ ์ธ ์๋ก JDBC
๋ฅผ ๋ค์ด๋ณผ ์ ์์ผ๋ฉฐ, ์๋น์ค ์ ๊ณต์ ํ๋ ์์ํฌ์๋ ๋ฐ๊ณผ ๊ฐ์ด ๋ค์ํ ๋ณํ๋ค์ด ์กด์ฌํ๋ค.
Bridge Pattern
Dependency Injection
java.util.ServiceLoader
- ๋ฒ์ฉ ์๋น์ค ์ ๊ณต์ ํ๋ ์์ํฌ
โ 3. ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋์ ๋จ์
1๏ธโฃ ์์์ ํ๋ ค๋ฉด public์ด๋ protected ์์ฑ์๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์, ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ง ์ ๊ณตํ๋ฉด ํ์ ํด๋์ค๋ฅผ ๋ง๋ค ์ ์๋ค.
์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ํด๋์ค์ ์ ์ฉํ ๋์๋ ์ฃผ๋ก private ์์ฑ์
๋ฅผ ์ ์ธํ์ฌ ์ฌ์ฉํ๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ง!!
์ ๊ณตํ๋ค๋ฉด, ํด๋น ํด๋์ค์ ํ์ ํด๋์ค๋ฅผ ์์ฑํ ์ ์๋ค๋ ๋จ์ ์ด ์๋ค.
ํ์ง๋ง ์ด์ฉ๋ฉด ์ด ์ ์ฝ์ ํตํด ์์๋ณด๋ค ์ปดํฌ์ง์
; item 18
์ ์ฌ์ฉํ๋๋ก ์ ๋ํ๊ณ , ๋ถ๋ณ ํ์
; item 17
๋ก ๋ง๋ค๋ ค๋ฉด
์ด ์ ์ฝ์ด ์คํ๋ ค ์ฅ์ ์ด ๋ ์๋ ์๋ค.
๐ค ๊ทธ๋ ๋ค๋ฉด ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ + public(protected) ์์ฑ์๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ ๊น?
A. ๊ตฌ๊ธ๋ง์ ํด๋ด๋ ์ ๋์ค์ง ์๋๋ค... ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋ชฉ์ ์ค ํ๋๊ฐ ์ ์ฝ์ ๊ฑฐ๋ ๊ฒ์ด๋ผ๋ฉด ๊ทธ๋ ๊ฒ ํด๋ ๋ ๊ฒ ๊ฐ์๋ฐ...!
์ด ๋ถ๋ถ์ ๋ํด์๋ ์ถ๊ฐ ์กฐ์ฌ๋ฅผ ์งํํ๊ณ , ๋ด์ฉ์ ์ถ๊ฐํด์ผ๊ฒ ๋ค!
2๏ธโฃ ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ์ฐพ๊ธฐ ํ๋ค๋ค.
์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ ์์ฑ์์ฒ๋ผ API ์ค๋ช ์ ๋ช ํํ ๋๋ฌ๋์ง ์๊ธฐ ๋๋ฌธ์, API ๋ฌธ์์ ๋ฉ์๋ ๋ค์ด๋ฐ ์ปจ๋ฒค์ ์ ํ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ์ํํด์ฃผ์ด์ผ ํ๋ค.
์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋์์ ์ฃผ๋ก ์ฌ์ฉํ๋ ๋ช ๋ช ๋ฐฉ์์ ์ฌ์ฉํ์ฌ ์กฐ๊ธ์ด๋ผ๋ ๋ฌธ์ ๋ฅผ ์ํํ ์ ์๋ค.
โ 4. ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋์์ ํํ ์ฌ์ฉํ๋ ๋ช ๋ช ๋ฐฉ์
- from
: ๋งค๊ฐ๋ณ์๋ฅผ ํ๋ ๋ฐ์์ ํด๋น ํ์
์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ ํ๋ณํ ๋ฉ์๋
Date date = Date.from(instant);
- of
: ์ฌ๋ฌ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ ์ ํฉํ ํ์
์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ ์ง๊ณ ๋ฉ์๋
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
- valueOf
: from๊ณผ of์ ๋ ์์ธํ ๋ฒ์
// valueOf()๋ผ๋ ๋ค์ด๋ฐ์ ํตํด ๊ฐ์ ๋ฐ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋ฉ์๋์์ ์ถ์ธกํ ์ ์๋ค.
String string = String.valueOf(3);
- instance
or getInstance
: ๋งค๊ฐ๋ณ์๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ๋งค๊ฐ๋ณ์๋ก ๋ช
์ํ ์ธ์คํด์ค๋ฅผ ๋ฐํํ์ง๋ง, ๊ฐ์ ์ธ์คํด์ค ์์ ๋ณด์ฅํ์ง ์๋๋ค.
- create
or newInstance
: getInstance
์ ์ ์ฌํ์ง๋ง, ๋งค๋ฒ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ฐํํจ์ ๋ณด์ฅํ๋ค.
// ํญ์ ์์ฑ์ ํค์๋(new)๋ฅผ ํตํด์ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ๋ฐํํ ๋ ์ฌ์ฉ
- getType
: getInstance
์ ๊ฐ์ผ๋, ์์ฑํ ํด๋์ค๊ฐ ์๋ ๋ค๋ฅธ ํด๋์ค์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ์ํ ๋ ์ฌ์ฉํ๋ค. ์ฌ๊ธฐ์ Type์ ํฉํฐ๋ฆฌ ๋ฉ์๋๊ฐ ๋ฐํํ ๊ฐ์ฒด์ ํ์
์ด๋ค.
// Files ํด๋์ค์ FileStore ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ฝ๋๊ฐ ์๊ณ , ํญ์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฐ์์ด ๋ณด์ฅ๋์ด์์ง ์์ ๋
FileStore fileStore = Files.getFileStore(path);
- newType
: newInstance
์ ๊ฐ์ผ๋, ์์ฑํ ํด๋์ค๊ฐ ์๋ ๋ค๋ฅธ ํด๋์ค์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ์ํ ๋ ์ฌ์ฉํ๋ค. ์ฌ๊ธฐ์ Type์ ํฉํฐ๋ฆฌ ๋ฉ์๋๊ฐ ๋ฐํํ ๊ฐ์ฒด์ ํ์
์ด๋ค.
// Files ํด๋์ค์ BufferedReader ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ฝ๋๊ฐ ์๊ณ , ํญ์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ฐํํจ์ด ๋ณด์ฅ๋์ด์์ ๋
BufferedReader reader = Files.newBufferedReader(path);
- type
: getType
๊ณผ newType
์ ๊ฐ๊ฒฐํ ๋ฒ์
// ๋ค๋ฅธ ํด๋์ค์์ ํน์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋ฉ์๋์ ์ฌ์ฉ
List<Complaint> litany = Collections.list(legacyLitany);