본문 바로가기

Java

람다 표현식을 활용한 디자인패턴 - 의무 체인 패턴

디자인 패턴은 유용하다.

람다 표현식을 디자인 패턴에 적용한다면 더 간결하게 구현할 수 있다.

 

의무 체인 패턴

한 객체가 어떤 작업을 처리하고 다른 객체로 결과를 전달하여 또 다른 작업을 처리할 때 사용된다.

 

자동차 객체가 있다고 가정하자. 자동차 객체는 연비와, 속도, 사이즈의 필드변수를 가지고 있다.

코드로 살펴보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Car {
    private int fuelEfficiency;
    private int speed;
    private int size;
 
    public Car(final int fuelEfficiency, final int speed, final int size) {
        this.fuelEfficiency = fuelEfficiency;
        this.speed = speed;
        this.size = size;
    }
 
    public int getSize() {
        return size;
    }
 
    public int getFuelEfficiency() {
        return fuelEfficiency;
    }
 
    public int getSpeed() {
        return speed;
    }
}

 

자동차객체를 튜닝하는 과정을 의무체인으로 구현해보려고 한다.

연비를 높여주는 객체, 속도를 올려주는 객체, 사이즈를 키우는 객체가 있다.

그리고 이 3개의 객체는 Tuner 라는 추상클래스로 묶여있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class Tuner {
    protected Tuner tuner;
 
    public void setTuner(Tuner tuner) {
        this.tuner = tuner;
    }
 
    public Car tuning(Car car) {
        Car newCar = upgrade(car);
        if (tuner != null) {
            return tuner.tuning(newCar);
        }
        return newCar;
    }
 
    abstract protected Car upgrade(Car car);
}

 

1
2
3
4
5
6
7
8
9
10
public class FuelEfficiencyUpgrader extends Tuner {
    @Override
    protected Car upgrade(Car car) {
        int efficiency = car.getFuelEfficiency();
        int speed = car.getSpeed();
        int size = car.getSize();
        return new Car(efficiency + 2, speed, size);
    }
}

 

1
2
3
4
5
6
7
8
9
10
public class SpeedUpgrader extends Tuner {
    @Override
    protected Car upgrade(Car car) {
        int efficiency = car.getFuelEfficiency();
        int speed = car.getSpeed();
        int size = car.getSize();
        return new Car(efficiency, speed + 10, size);
    }
}

 

1
2
3
4
5
6
7
8
9
10
public class SizeUpgrader extends Tuner {
    @Override
    protected Car upgrade(Car car) {
        int efficiency = car.getFuelEfficiency();
        int speed = car.getSpeed();
        int size = car.getSize();
        return new Car(efficiency, speed, size + 1);
    }
}

 

위의 코드를 실행하는 Main 클래스는 다음과 같다.

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
28
29
public class Main {
    public static void main(String[] args) {
        Car car = new Car(1090, 1);
        System.out.println("연비 : " + car.getFuelEfficiency());
        System.out.println("속도 : " + car.getSpeed());
        System.out.println("크기 : " + car.getSize());
 
        Tuner fuelEfficiencyTuner = new FuelEfficiencyUpgrader();
        Tuner speedTuner = new SpeedUpgrader();
        Tuner sizeTuner = new SizeUpgrader();
 
        fuelEfficiencyTuner.setTuner(speedTuner);
        speedTuner.setTuner(sizeTuner);
 
        Car newCar = fuelEfficiencyTuner.tuning(car);
        System.out.println("업그레이드된 차의 연비 : " + newCar.getFuelEfficiency());
        System.out.println("업그레이드된 차의 속도 : " + newCar.getSpeed());
        System.out.println("업그레이드된 차의 크기 : " + newCar.getSize());
 
 
        //출력 결과
//        연비 : 10
//        속도 : 90
//        크기 : 1
//        업그레이드된 차의 연비 : 12
//        업그레이드된 차의 속도 : 100
//        업그레이드된 차의 크기 : 2
    }
}

 

람다 표현식 사용

람다 표현식을 사용한다면 Tuner 와 Tuner 를 상속받는 클래스들 없이 Car 객체를 튜닝할 수 있다.

우리에게 필요한 건 단지 Car 객체와 람다 표현식을 사용한 Main 클래스 뿐이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Car {
    private int fuelEfficiency;
    private int speed;
    private int size;
 
    public Car(final int fuelEfficiency, final int speed, final int size) {
        this.fuelEfficiency = fuelEfficiency;
        this.speed = speed;
        this.size = size;
    }
 
    public int getSize() {
        return size;
    }
 
    public int getFuelEfficiency() {
        return fuelEfficiency;
    }
 
    public int getSpeed() {
        return speed;
    }
}
 
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
28
29
30
31
32
33
34
import java.util.function.Function;
import java.util.function.UnaryOperator;
 
public class Main {
    public static void main(String[] args) {
        Car oldCar = new Car(10901);
        System.out.println("연비 : " + oldCar.getFuelEfficiency());
        System.out.println("속도 : " + oldCar.getSpeed());
        System.out.println("크기 : " + oldCar.getSize());
 
        UnaryOperator<Car> fuelEfficiencyTuner =
                car -> new Car(car.getFuelEfficiency() + 2, car.getSpeed(), car.getSize());
        UnaryOperator<Car> speedTuner =
                car -> new Car(car.getFuelEfficiency(), car.getSpeed() + 10, car.getSize());
        UnaryOperator<Car> sizeTuner =
                car -> new Car(car.getFuelEfficiency(), car.getSpeed(), car.getSize() + 1);
 
        Function<Car, Car> pipeLine =
                fuelEfficiencyTuner.andThen(speedTuner).andThen(sizeTuner);
 
        Car newCar = pipeLine.apply(oldCar);
        System.out.println("업그레이드된 차의 연비 : " + newCar.getFuelEfficiency());
        System.out.println("업그레이드된 차의 속도 : " + newCar.getSpeed());
        System.out.println("업그레이드된 차의 크기 : " + newCar.getSize());
 
        //출력 결과
//        연비 : 10
//        속도 : 90
//        크기 : 1
//        업그레이드된 차의 연비 : 12
//        업그레이드된 차의 속도 : 100
//        업그레이드된 차의 크기 : 2
    }
}

 

※ 람다 표현식을 사용하는 것이 항상 좋은 것은 아니다.

불필요한 코드를 제거할 수 있어서 람다 표현식이 유용할 수 있고, 경우에 따라 기존의 방식을 고수하는 것이 더 좋을 수 있다.

반응형