[사이드 프로젝트] 함수형 프로그래밍 익히기 With Java - Constructor & Factory Pattern

gimseonjin616·2022년 5월 14일
0

Factory Pattern

팩토리 패턴은 객체 생성을 추상화하여 한 군데서 관리하는 패턴으로 상속 관계에 있는 두 객체에서 상위 객체가 추상화된 생성화 부분을, 하위 객체과 구체적인 구현을 담당한다.

상위 객체는 세부 구현 내용을 몰라도 되고 하위 객체에서 코드 수정이 생기면 그 부분만 수정하면 되기 때문에 두 객체의 의존성이 줄어든다.

이번 시간에는 이 Factory Pattern을 활용하여 객체 생성하는 부분을 함수형으로 프로그래밍해볼 것이다.

우선 지난 시간에 구현한 Car을 Abstract Class로 변경하고 각각 SUV, Sedan, Ven 객체를 구현한다.

public abstract class Car {
    protected String name;
    protected String brand;

    public Car(String name, String brand) {
        this.name = name;
        this.brand = brand;
    }

    public abstract void drive();
}

public class Sedan extends Car{

    public Sedan(String name, String brand) {
        super(name, brand);
    }

    @Override
    public void drive() {
        System.out.println("SUV : " + name + " from " + brand);
    }
}

public class SUV extends Car{

    public SUV(String name, String brand) {
        super(name, brand);
    }

    @Override
    public void drive() {
        System.out.println("SUV : " + name + " from " + brand);
    }
}

public class Ven extends Car{

    public Ven(String name, String brand) {
        super(name, brand);
    }

    @Override
    public void drive() {
        System.out.println("SUV : " + name + " from " + brand);
    }
}

이제 이 Car를 만드는 CarFactory를 만들어본다.

팩토리 클래스는 주로 Static method를 사용하며 차후 Car 종류가 추가됐을 때, 내부 코드 수정이 아니라 타입 추가하는 방식으로 만들기 위해 map을 사용한다.

public class CarFactory {

    private static Map<String, BiFunction<String, String, Car>> cars;

    static {
        cars = new HashMap<>();
        cars.put("suv", SUV::new);
        cars.put("sedan", Sedan::new);
        cars.put("ven", Ven::new);
    }

    public static Car create(String type, String name, String brand) {
        try {
            return cars.get(type).apply(name, brand);
        } catch (NullPointerException e) {
            throw new IllegalArgumentException("해당하는 차가 없습니다!");
        }
    }
}

그리고 다음과 같이 Input List가 주어지면 만들어진 Factory Class로 Car class 들을 만들 수 있다.

public class main {
    public static void main(String[] args){
        String [][] inputs = new String[][] {
                {"ven", "Sienna", "Toyota"},
                {"sedan", "Sonata", "Hyundai"},
                {"sedan", "Model 5", "Tesla"},
                {"suv", "Sorento", "KIA"}
        };

        List<Car> cars = new ArrayList<>();

        for(String[] i : inputs){
            cars.add(CarFactory.create(i[0], i[1], i[2]));
        }

        System.out.println(cars);
    }
}

Map 함수를 활용한 리팩토링

Map 함수는 ForEach 함수와 비슷하게 리스트와 함수를 파라미터로 받아 각 요소별로 함수를 수행한다.

여기서 ForEach 가장 중요한 차이점이 있는데 바로 수행한 결과를 배열에 담아서 반환한다.

ForEach는 단순히 수행만하고 끝이나지만 Map 함수는 수행한 결과값을 새로운 배열에 담아서 반환한다.

위 코드를 Map 함수를 구현해서 리팩토링해보겠다.

우선 Car Class에서 create 부분은 파라미터가 3개여서 TriFuction Interface를 만들거나 파라미터가 하나인 함수를 오버로딩해서 구현해야하는데 오버로딩 방법을 써서 새로운 create를 만든다.

    public static Car create(String[] args) {
        try {
            return cars.get(args[0]).apply(args[1], args[2]);
        } catch (NullPointerException e) {
            throw new IllegalArgumentException("해당하는 차가 없습니다!");
        }
    }

Map 함수를 구현하면 아래와 같다.

    public static <T> List<T> map(String[][] list, Function<String[], T> processor){
        List<T> newList = new ArrayList<>();

        for(String[] t : list){
            newList.add(processor.apply(t));
        }

        return newList;
    }

그 후, map 함수를 사용해서 기존 코드를 수정하면 아래와 같다.

public class main {
    public static void main(String[] args){
        String [][] inputs = new String[][] {
                {"ven", "Sienna", "Toyota"},
                {"sedan", "Sonata", "Hyundai"},
                {"sedan", "Model 5", "Tesla"},
                {"suv", "Sorento", "KIA"}
        };

        List<Car> cars = map(inputs, CarFactory::create);

        System.out.println(cars);
    }

    public static <T> List<T> map(String[][] list, Function<String[], T> processor){
        List<T> newList = new ArrayList<>();

        for(String[] t : list){
            newList.add(processor.apply(t));
        }

        return newList;
    }
}
profile
to be data engineer

0개의 댓글