Post

⛓️ Java Design-Pattern 05 - Factory Method

⛓️ Java Design-Pattern 05 - Factory Method

πŸ“— γ€ŽJAVA μ–Έμ–΄λ‘œ λ°°μš°λŠ” λ””μžμΈ νŒ¨ν„΄ : μ‰½κ²Œ λ°°μš°λŠ” GoF의 23κ°€μ§€ λ””μžμΈ νŒ¨ν„΄γ€λ₯Ό 읽고 μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€.

Factory Method νŒ¨ν„΄μ΄λž€?

  • μΈμŠ€ν„΄μŠ€ 생성 방법을 μƒμœ„ ν΄λž˜μŠ€μ—μ„œ κ²°μ •ν•˜λ˜, μ‹€μ œ μΈμŠ€ν„΄μŠ€λŠ” ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μƒμ„±ν•œλ‹€.
  • 즉 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 곡μž₯을 Template MethodΒ νŒ¨ν„΄μœΌλ‘œ κ΅¬μ„±ν•œ 것이닀.

예제 ν”„λ‘œκ·Έλž¨

  • frameworkΒ νŒ¨ν‚€μ§€μ— ν¬ν•¨λœΒ Product,Β FactoryΒ ν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” λΌˆλŒ€ 역할을 ν•œλ‹€.
  • idcardΒ νŒ¨ν‚€μ§€μ— ν¬ν•¨λœΒ IDCard,Β IDCardFactoryΒ ν΄λž˜μŠ€λŠ” ꡬ체적인 λ‚΄μš©μ„ κ΅¬ν˜„ν•˜λŠ” 역할을 ν•œλ‹€.
  • MainΒ ν΄λž˜μŠ€λŠ” λ™μž‘ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ ν΄λž˜μŠ€μ΄λ‹€.

Product 클래슀

1
2
3
4
5
package framework;

public abstract class Product {
	public abstract void use();
}
  • 이 ν”„λ ˆμž„μ›Œν¬μ—μ„œλŠ” 무엇이든 useν•  수 μžˆλŠ” 것을 μ œν’ˆμœΌλ‘œ κ·œμ •ν•œλ‹€.

Factory 클래슀

1
2
3
4
5
6
7
8
9
10
11
12
package framework;

public abstract class Factory {
	public final Product create(String owner) {
    	Product p = createProduct(owner);
        registerProduct(p);
        return p;
    }
    
    protected abstract Product createProduct(String owner);
    protected abstract void registerProduct(String product);
}
  • Template MethodΒ νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬Β createΒ λ©”μ†Œλ“œλ₯Ό 톡해 ProductΒ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.Β 
  • createΒ λ©”μ†Œλ“œ λ‚΄Β createProduct,Β registerProductΒ λ©”μ†Œλ“œλŠ” 좔상 λ©”μ†Œλ“œλ‘œ μ„ μ–Έλ˜μ–΄ μžˆλ‹€.
  • 이처럼 Factory MethodΒ νŒ¨ν„΄μ€ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•ŒΒ Template MethodΒ νŒ¨ν„΄μ„ μ‚¬μš©ν•œλ‹€.

IDCard 클래슀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package idcard;

import framework.Product;

public class IDCard extends Product {
	private String owner;
    
    IDCard(String owner) {
    	System.out.println(owner + "의 μΉ΄λ“œλ₯Ό λ§Œλ“­λ‹ˆλ‹€.");
        this.owner = owner;
    }
    
    @Override
    public void use() {
    	System.out.println(this + "을 μ‚¬μš©ν•©λ‹ˆλ‹€.");
    }
    
    @Override
    public String toString() {
    	return "[IDCard:" + owner + "]"
    }
    
    public String getOwner() {
    	return owner;
    }
}
  • Product 클래슀의 ν•˜μœ„ ν΄λž˜μŠ€λ‘œμ„œ μ •μ˜λœ ν΄λž˜μŠ€μ΄λ‹€.

IDCardFactory 클래슀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package idcard;

import framework.Factory;
import framework.Product;
import java.util.ArrayList;
import java.util.List;

public class IDCardFactory extends Factory {
    private List<String> owners = new ArrayList<>();
    
    @Override
    protected Product createProduct(String owner) {
        return new IDCard(owner);
    }
    
    @Override
    protected void registerProduct(Product product) {
        if (product instanceof IDCard) {
            IDCard card = (IDCard) product;
            owners.add(card.getOwner());
        }
    }
    
    public List<String> getOwners() {
        return owners;
    }
}

Main 클래슀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import framework.Factory;
import framework.Product;
import idcard.IDCardFactory;

public class Main {
	public static void main(String args[]) {
    	Factory factory = new IDCardFactory();
        Product card1 = factory.create("κΉ€μ•„λ¬΄κ°œ");
        Product card2 = factory.create("λ°•μ•„λ¬΄κ°œ");
        Product card3 = factory.create("μ΅œμ•„λ¬΄κ°œ");
        
        card1.use();
        card2.use();
        card3.use();
    }
}
  • μ‹€μ œλ‘œΒ IDCardFactoryΒ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ–΄ μ‚¬μš©ν•˜λŠ” λ™μž‘ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ ν΄λž˜μŠ€μ΄λ‹€.

Factory MethodΒ νŒ¨ν„΄μ˜ λ“±μž₯인물

Product 클래슀

  • ν”„λ ˆμž„μ›Œν¬μ— ν•΄λ‹Ήλ˜λ©°, μ œν’ˆμ—­ν• λ‘œ, 이 νŒ¨ν„΄μœΌλ‘œ μƒμ„±λ˜λŠ” μΈμŠ€ν„΄μŠ€κ°€ κ°€μ Έμ•Ό ν•  μΈν„°νŽ˜μ΄μŠ€Β APIλ₯Ό κ²°μ •ν•˜λŠ” 좔상 ν΄λž˜μŠ€μ΄λ‹€.

Factory 클래슀

  • ν”„λ ˆμž„μ›Œν¬μ— ν•΄λ‹Ήλ˜λ©°, μ œν’ˆ 역할을 μƒμ„±ν•˜λŠ” μž‘μ„±μžΒ Creator 역할을 ν•œλ‹€.
  • μ‹€μ œλ‘œ 생성할 ConcreteProductΒ μ—­ν• μ—λŠ” μ•„λŠ” λ°”κ°€ μ—†λ‹€.
  • 예제 ν”„λ‘œκ·Έλž¨μ—μ„œλŠ”Β newΒ λŒ€μ‹ Β createProductΒ λ©”μ†Œλ“œλ₯Ό 톡해 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ”λ°, 이λ₯Ό 톡해 ꡬ체적인 클래슀 λͺ…에 μ˜μ‘΄ν•˜μ§€ μ•Šμ„ 수 있게 λœλ‹€.
IDCard 클래슀
  • ꡬ체적인 μ œν’ˆΒ ConcreteProduct 역할을 λ§‘μ•„ μ œν’ˆ μ—­ν• μ˜ ꡬ체적인 κ΅¬ν˜„μ„ μˆ˜ν–‰ν•œλ‹€.
IDCardFactory 클래슀
  • ꡬ체적인 μž‘μ„±μžΒ ConcreteCreator 역할을 λ§‘μ•„ μž‘μ„±μž μ—­ν• μ˜ ꡬ체적인 κ΅¬ν˜„μ„ μˆ˜ν–‰ν•œλ‹€.

μ±…μ—μ„œ μ œμ‹œν•˜λŠ” 힌트

ν”„λ ˆμž„μ›Œν¬μ™€ ꡬ체적인 λ‚΄μš©

  • μ—¬κΈ°μ„œ 같은 ν”„λ ˆμž„ μ›Œν¬λ₯Ό μ‚¬μš©ν•˜μ—¬Β IDCardκ°€ μ•„λ‹ŒΒ TVλ₯Ό λ§Œλ“ λ‹€κ³  κ°€μ •ν•΄λ³΄μž.
  • 이 경우 frameworkΒ νŒ¨ν‚€μ§€λ₯ΌΒ importν•˜λŠ” λ³„κ°œμ˜Β televisionΒ νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€κ²Œ λœλ‹€.
  • 그런데,Β frameworkΒ νŒ¨ν‚€μ§€ λ‚΄ ν΄λž˜μŠ€λ“€μ€ μˆ˜μ •ν•  ν•„μš”κ°€ μ—†λ‹€.
  • μ™œλƒν•˜λ©΄Β frameworkΒ νŒ¨ν‚€μ§€ λ‚΄μ—μ„œλŠ”Β idcardΒ νŒ¨ν‚€μ§€λ₯ΌΒ importΒ ν•œ 적이 μ—†λ‹€.
  • 즉 ν•΄λ‹Ή νŒ¨ν„΄μ—μ„œ ν”„λ ˆμž„μ›Œν¬λŠ” ꡬ체적인 λ‚΄μš©μ— μ˜μ‘΄ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것을 μ•Œ 수 μžˆλ‹€.

μΈμŠ€ν„΄μŠ€ 생성: λ©”μ†Œλ“œ κ΅¬ν˜„ 방법

  • μΈμŠ€ν„΄μŠ€ 생성 λ©”μ†Œλ“œλ₯Ό κΈ°μˆ ν•˜λŠ” 방법은 λ‹€μŒ 두 κ°€μ§€λ‘œ 생각할 수 μžˆλ‹€.
1
2
3
4
5
6
7
8
9
10
11
12
13
/* 1. 좔상 λ©”μ†Œλ“œλ‘œ 기술 */
abstract class Factory {
	public abstract Product createProduct(String name);
	
    // ...
}

/* 2. λ””ν΄νŠΈ κ΅¬ν˜„μ„ μ€€λΉ„ */
class Factory {
	public Product createProduct(String name) {
    	return new Product(name);
    }
}
  • 좔상 λ©”μ†Œλ“œλ‘œ κΈ°μˆ ν•˜λŠ” 경우 예제 ν”„λ‘œκ·Έλž¨μ—μ„œ μ‚¬μš©ν•œ λ°©λ²•μœΌλ‘œ, 좔상 λ©”μ†Œλ“œλ‘œ κΈ°μˆ ν•  경우 κ΅¬ν˜„λ˜μ–΄ μžˆμ§€ μ•Šλ”λΌλ„ μ»΄νŒŒμΌν•  λ•Œ κ²€μΆœλœλ‹€λŠ” μž₯점이 μžˆλ‹€.
  • λ””ν΄νŠΈ κ΅¬ν˜„μ„ μ€€λΉ„ν•˜λŠ” 경우 ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„ν•˜μ§€ μ•Šλ”λΌλ„ λ””ν΄νŠΈ κ΅¬ν˜„μ΄ μ‚¬μš©λœλ‹€λŠ” μž₯점이 μžˆλ‹€.
  • λ‹€λ§Œ,Β ProductΒ ν΄λž˜μŠ€μ— λŒ€ν•΄ 직접 newλ₯Ό μ‹€ν–‰ν•˜μ—¬ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λ―€λ‘œΒ Product 클래슀λ₯Ό 좔상 클래슀둜 λ‘˜ 수 μ—†λ‹€.

νŒ¨ν„΄ 이용과 개발자 κ°„μ˜ μ˜μ‚¬μ†Œν†΅

  • ν•˜λ‚˜μ˜ 클래슀만 μ½μ–΄μ„œλŠ” λ™μž‘μ„ 잘 이해할 수 μ—†λ‹€.
  • μƒμœ„ ν΄λž˜μŠ€μ—μ„œ λ™μž‘μ˜ λΌˆλŒ€λ₯Ό μ΄ν•΄ν•œ ν›„ κ±°κΈ°μ—μ„œ μ‚¬μš©λ˜λŠ” 좔상 λ©”μ†Œλ“œκ°€ 무엇인지 ν™•μΈν•˜κ³ , λ‹€μ‹œ κ·Έ 좔상 λ©”μ†Œλ“œλ₯Ό μ‹€μ œλ‘œ κ΅¬ν˜„ν•˜λŠ” 클래슀의 μ†ŒμŠ€ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄μ•„μ•Ό ν•œλ‹€.
  • 일반적으둜 λ””μžμΈ νŒ¨ν„΄μ„ μ‚¬μš©ν•΄ μ–΄λ–€ 클래슀 ꡰ을 섀계할 경우, μ„€κ³„μžκ°€ λ³΄μˆ˜μžμ—κ²Œ μ˜λ„ν•œ λ””μžμΈ νŒ¨ν„΄μ΄ 무엇인지 잘 전달할 ν•„μš”κ°€ μžˆλ‹€.
  • κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ μ„€κ³„μžμ˜ μ˜λ„μ—μ„œ λ²—μ–΄λ‚œ μˆ˜μ •μ΄ κ°€ν•΄μ§ˆ 수 μžˆλ‹€.
  • μ£Όμ„μ΄λ‚˜ 개발 λ¬Έμ„œμ— μ‹€μ œλ‘œ μ‚¬μš©λ˜λŠ” λ””μžμΈ νŒ¨ν„΄μ˜ λͺ…μΉ­κ³Ό μ˜λ„λ₯Ό κΈ°μˆ ν•˜μ—¬ λ‘λŠ” 것도 쒋은 방법이닀.

static Factory Method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 1. java.security.SecureRandom */
SecureRandom random = SecureRandom.getInstance("NativePRNG");

/* 2. java.util.List */
List<String> list = List.of("Alice", "Bob");

/* 3. java.util.Arrays */
String[] arr = {"Alice", "Bob"};
List<String> list = Arrays.asList(arr);

/* 4. java.lang.String */
String string = String.valueOf('A');

/* 5. java.time.Instant */
Instant instant = Instant.now();
  • μΈμŠ€ν„΄μŠ€ 생성을 μœ„ν•œΒ staticΒ λ©”μ†Œλ“œ μ „λ°˜μ„Β Factory Method라고 λΆ€λ₯΄λŠ” κ²½μš°κ°€ μ‘΄μž¬ν•œλ‹€.
  • 이것은 GoF의 Factory MethodΒ νŒ¨ν„΄κ³ΌλŠ” λ‹€λ₯΄μ§€λ§ŒΒ Javaμ—μ„œ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ 자주 μ‚¬μš©λ˜λŠ” 기법이닀.
  • Java APIΒ λž˜νΌλŸ°μŠ€μ—μ„œλ„ μΈμŠ€ν„΄μŠ€ 생성을 μœ„ν•œ 클래슀 λ©”μ†Œλ“œλ₯ΌΒ static Factory Method둜 ν‘œν˜„ν•˜κΈ°λ„ ν•˜λ―€λ‘œΒ Java API 레퍼런슀λ₯Ό 읽을 λ•ŒλŠ” μ°Έμ‘°ν•˜λŠ” ν΄λž˜μŠ€μ—Β static Factory Methodκ°€ μ œκ³΅λ˜λŠ”μ§€ μ£Όλͺ©ν•΄μ•Ό ν•œλ‹€.
  • create,Β newInstance,Β getInstanceΒ λ“±μ˜ 이름이 자주 μ‚¬μš©λ˜μ§€λ§Œ, κ·Έ λ°–μ˜ 이름이 μ‚¬μš©λ˜λŠ” κ²½μš°λ„ μžˆλ‹€.
This post is licensed under CC BY 4.0 by the author.