클래스의 인스턴스를 얻는 전통적인 수단은 public생서자다
클래스는 생성자와 별도로 정적 팩터리 메서드를 제공할수 있다
정적 팩터리 메서드가 생성자 보다 좋은점
1. 이름을 가질수있다
public class Student {
private String name;
private int age;
private char gender;
// 디폴트 생성자
public Student(){
}
//매개변수 생성자
public Student(String name) {
this.name = name;
}
//팩토리메서드를 이용한 초기화
public static Student createStudentName(String name){
return new Student(name);
}
}
2. 호출될때마다 인스턴스를 새로 생성하지 않아도 된다
public final class Boolean implements java.io.Serializable, Comparable<Boolean> {
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
...
객체 안에 미리 정의된 static final 상수 객체를 반환, 매번 새로운 객체를 만들지 않는다.
3. 반환 타입의 하위 타입의 객체를 반환할 수 있는 능력이 있다.
class Animal {
public void speak() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Dog barks");
}
public void fetch() {
System.out.println("Dog fetches a ball");
}
}
class Cat extends Animal {
@Override
public void speak() {
System.out.println("Cat meows");
}
public void scratch() {
System.out.println("Cat scratches");
}
}
public class AnimalTest {
public static Animal getAnimal(String type) {
if ("dog".equalsIgnoreCase(type)) {
return new Dog();
} else if ("cat".equalsIgnoreCase(type)) {
return new Cat();
} else {
return new Animal();
}
}
public static void main(String[] args) {
Animal animal1 = getAnimal("dog");
Animal animal2 = getAnimal("cat");
animal1.speak(); // 출력값: Dog barks
animal2.speak(); // 출력값: Cat meows
if (animal1 instanceof Dog) {
((Dog) animal1).fetch(); // 출력값: Dog fetches a ball
} else if (animal1 instanceof Cat) {
((Cat) animal1).scratch();
}
if (animal2 instanceof Dog) {
((Dog) animal2).fetch();
} else if (animal2 instanceof Cat) {
((Cat) animal2).scratch(); // 출력값: Cat scratches
}
}
}
이 예시는 Animal 클래스와 Dog 및 Cat이라는 두 개의 하위 클래스가 있다.
getAnimal 메소드는 Animal 클래스의 객체를 반환하지만 , Animal의 하위 유형이기 때문에 실제로 Dog 또는 Cat의 인스턴스도 반환할 수 있다.
각각 'Dog'와 'Cat'의 인스턴스인 'animal1'과 'animal2' 모두에서 'speak' 메서드를 호출하여 이를 보여준다.
반환타이의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하던 상관없다
class Shape {
public void draw(){
System.out.println("모양을 그리다");
}
}
class Circle extends Shape{
@Override
public void draw() {
System.out.println("원을 그리다");
}
}
class Retangle extends Shape
{
@Override
public void draw() {
System.out.println("직사각형을 그리다");
}
}
public class ShapeFactory{
public Shape createShape(String shapeType){
if("circle".equalsIgnoreCase(shapeType)){
return new Circle();
} else if ("retangle".equalsIgnoreCase(shapeType)) {
return new Retangle();
}else {
return new Shape();
}
}
public static void main(String[] args) {
ShapeFactory shapeFactory= new ShapeFactory();
Shape shape1= shapeFactory.createShape("circle");
Shape shape2= shapeFactory.createShape("retangle");
Shape shape3= shapeFactory.createShape("triangle");
shape1.draw();
shape2.draw();
shape3.draw();
}
}
위 예시는 Shape 기본 클래스와 Circle 및 Rectangle이라는 두 개의 하위 클래스가 있고, ShapeFactory 클래스에는 shapeType 매개변수를 사용하는 createShape 메서드가 있다. shapeType 값에 따라 적절한 클래스(Circle, Rectangle 또는 기본 Shape)의 인스턴스를 반환한다.
다양한 입력 매개변수로 createShape를 호출하면 다양한 클래스의 객체를 반환할 수 있다.
이는 Java에서 메소드 오버로딩을 사용하여 입력 매개변수를 기반으로 다양한 클래스의 객체를 반환하는 방법을 보여주고있다.
5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재 하지 않아도 된다
Java에서는 리플렉션 및 동적 클래스 로딩을 사용하여 컴파일 타임에 존재할 필요가 없는 클래스의 인스턴스를 생성할 수 있다
Shape라는 인터페이스가 있다고 가정할때
public interface Shape {
void draw();
}
이제 컴파일 타임에 해당 클래스가 알려지지 않은 경우에도 이 'Shape' 인터페이스를 구현하는 클래스의 인스턴스를 반환할 수 있는 정적 팩토리 메서드를 생성.
리플렉션 및 동적 클래스 로딩을 사용하여 구현할수있다.
import java.lang.reflect.InvocationTargetException;
public class ShapeFactory {
public static Shape createShape(String className) {
try {
//리플렉션을 사용하여 클래스를 동적으로 로드
Class<?> shapeClass = Class.forName(className);
//클래스의 인스턴스 만들기
Object instance = shapeClass.getDeclaredConstructor().newInstance();
// 인스턴스가 Shape 객체인지 체크
if (instance instanceof Shape) {
return (Shape) instance;
} else {
throw new IllegalArgumentException("\n" + "클래스가 Shape 인터페이스를 구현하지 않습니다");
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
// 팩토리를 이용해 동적으로 생성
Shape circle = ShapeFactory.createShape("Circle");
Shape triangle = ShapeFactory.createShape("Triangle");
if (circle != null) {
circle.draw();
} else {
System.out.println("원을 만들수없다");
}
if (triangle != null) {
triangle.draw();
} else {
System.out.println("삼각형을 만들수 없다");
}
}
}