[디자인패턴] Factory Method
FactoryMethod
4-1) 예제 프로그램에서는 IDCard 클래스의 생성자는 public이 아닙니다. 이것은 무엇을 나타내고 있습니까?
public class IDCard extends Product {
...
IDCard(String owner) {
...
this.owner = owner;
}
...
}
위와 같이 앞에 아무런 접근제어자가 붙어있지 않은 경우라면, 디폴트로 package 접근이라고 볼 수 있습니다.
package : 같은 패키지에 선언되어있는 다른 클래스까지만 접근이 허용된다.
따라서 IDCard의 인스턴스는 패키지 외부로부터 보호되어있기 때문에, 같은 패키지에 있는 IDCardFactory를 경유해야합니다. → 유지보수성
+) 만약 생성자가 public이라면?
//기존 Main
Factory factory = new IDCardFactory();
Product card1 = factory.create("홍길동");
//만약 public이라면?
IDCard idcard = new IDCard("홍길동");
위와 같이 new를 사용해서 객체를 생성하게 되는데, 만약 이렇게 될 시 IDCard 클래스에 변경사항이 생긴다면 바꿔야할 코드가 늘어납니다.
→ 유지보수에 적합하지 않습니다.
4-2) 예제 프로그램의 IDCard 클래스에 카드의 인증번호를 붙이고, IDCardFactory 클래스가 인증번호와 소지자의 대응표를 갖도록 수정해보십시오.
→ 문제의도 : IDCard클래스와 IDCardFactory클래스를 수정해도 프레임워크 쪽과 Main클래스의 소스코드를 수정할 필요가 전혀 없다는 점!
정답코드 😎
IDCard.java
package idcard;
import framework.*;
public class IDCard extends Product {
private String owner;
private int serial;
IDCard(String owner, int serial) {
System.out.println(owner + "(" + serial + ")" + "의 카드를 만듭니다.");
this.owner = owner;
this.serial = serial;
}
public void use() {
System.out.println(owner + "(" + serial + ")" + "의 카드를 사용합니다.");
}
public String getOwner() {
return owner;
}
public int getSerial() {
return serial;
}
}
IDFactory.java
package idcard;
import framework.*;
import java.util.*;
public class IDCardFactory extends Factory {
//HashMap 사용: serial번호(Integer), 이름(String)
private HashMap<Integer, String> database = new HashMap<Integer, String>();
private int serial = 100;
//synchronized
protected synchronized Product createProduct(String owner) {
return new IDCard(owner, serial++);
}
protected void registerProduct(Product product) {
IDCard card = (IDCard)product;
database.put(new Integer(card.getSerial()), card.getOwner());
}
public HashMap<Integer, String> getDatabase() {
return database;
}
}
+ HashMap
HashMap은 Map 인터페이스를 구현하고 있는 대표적인 클래스입니다. 그리고 Map의 구조인 key-value쌍으로 구성되어 있습니다.
그리고 Map의 대표적인 특징은 하나의 key는 정확히 하나의 value만 가질 수 있다는 것입니다.
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
}
→ 여기에서 자세히 확인
+ Synchronized?
- 교수님이 강의에서 예로 설명해주신 은행계좌에 100만원 넣기
- 스레드간 동기화가 되지 않은 상태에서 멀티스레드 프로그램을 돌리면, data의 안정성과 신뢰성을 보장할 수 없습니다.
- 따라서 자바에서는 synchronized 키워드를 제공 : 여러개의 스레드가 한 개의 자원을 사용하고자 할 때, 현재 데이터를 사용하고 있는 해당 스레드를 제외하고 나머지 스레드들은 데이터에 접근할 수 없도록 막는 개념
// method에서의 synchronized 사용
public synchronized void method(){ ... }
//class에서의 synchronized 사용
private Object obj = new Object();
public void Class(){
synchronized(obj){ ... }
}
4-3) Product 클래스의 하위 클래스에서는 생성자에서 반드시 ‘제품의 이름'을 인수로 부여하도록 다음과 같이 Product 클래스를 정의했습니다. 그러나 컴파일할 때 에러가 발생했습니다. 이유가 무엇입니까?
public abstract class Product {
public abstract Product(String name);
public abstract void use();
}
생성자는 상속이 가능한가?
→ 생성자는 상속이 되지 않습니다. 대신 자식 클래스로 인스턴스를 생성할 때 자동으로 상위클래스의 생성자를 호출하게 됩니다.
따라서 abstract한 생성자는 의미가 없습니다.
위와 같은 경우에서는 이름을 인수로 부여하기 위해선 생성자가 아닌, 메소드를 별도로 선언해야합니다.
발표자료
https://elfin-roadway-384.notion.site/3-24-FactoryMethod-Singleton-5782f8e834f1482fa3c932914496cb94
3/24 디자인패턴 - FactoryMethod, Singleton
4장 FactoryMethod
elfin-roadway-384.notion.site