2015년 7월 21일 화요일

디자인패턴1. Strategy Pattern

디자인 패턴에 대해서 좀 더 몸에 익히기 위해서 분석을 하고 예제를 통해서 몸에 익히도록 해본다.

- Strategy Pattern
  • defines a family of algorithms,
  • encapsulates each algorithm, and
  • makes the algorithms interchangeable within that family.

위키피아의 원문 내용이다. 

  - 상속 알로리즘을 정의
  - 각 알고리즘을 캘슐화 해라 (다른 부분에 대해서 캡슐화 하여 분리 시킴)
  - 내부적으로 변경이 가능하도록 알고리즘을 구성해라

  
Spring의 DI개념이 해당 패턴을 이용하여 만들어 구성한 것이라고 볼 수 있다.

(1) 변하는 부분 캡슐화
변경이 필요한 부분에 대해서 interface를 통해서 행위에 대해서 정의를 하고 구현체에 역활을 넘긴다. 

아래의 이미지를 참고하면 
excute라는 공통된 행위에 대해서 interface로 정의를 하고 각각 다른 전략진행하는 A, B를 나눈다. 
해당 strategy 를 이용하여 다른 객체에서 excute를 실행하면 실행하는 객체는 실제 excute의 각기 다른 행위에 대해서는 인지하지 않고 excute라는 행위의 결과에 대해서 처리를 할수 있도록 한다. 

(2) 인터페이스에 위임

 Customer에서 가격 측정을 위한 데이타는 BillingStrategy라는 Interface를 위임하고 
실제 특정 상황에 따라 각각의 맞는 가격전략을 위임하도록 한다. 

아래는 wiki예제를 클래스 다이어 그램으로 표현하였다.


Customer는 BillingStrategy를 가지고 있으면 printBill을 할때 BillingStrategy의 getActPrice를 통하여 실제 가격을 가져올때 여러가지 가격 전략에 따라 가격이 다르게 측정된다. 

이때 BillingStrategy interface를 구현하여 여러가지 가격 전략을 생성하고 Customer는 상황에 맞는 전략을 가져와 가격을 측정하도록 한다. 

이와 같이 특정 행위에 대해서 interface를 통하여 정의를 하고 구현체를 통해서 구현을 함으로써 각 가격을 가져오는 것에 대해서 캡슐화를 진행하여 Customer는 해당 행위에 대해서 전혀 모르게 하고 행위만 진행할 수 있도록 설계를 해야 하는 것이 중요하다. 



wiki 예제

package com.mike.designPattern.strategy;
import java.util.ArrayList;
import java.util.List;

public class Strategy {

    public static void main(String[] args) {
        Customer a = new Customer(new NormalStrategy());

        // Normal billing
        a.add(1.0, 1);

        // Start Happy Hour
        a.setStrategy(new HappyHourStrategy());
        a.add(1.0, 2);

        // New Customer
        Customer b = new Customer(new HappyHourStrategy());
        b.add(0.8, 1);
        // The Customer pays
        a.printBill();

        // End Happy Hour
        b.setStrategy(new NormalStrategy());
        b.add(1.3, 2);
        b.add(2.5, 1);
        b.printBill();

    }
}

class Customer {

    private List<Double> drinks;
    private BillingStrategy strategy;

    public Customer(BillingStrategy strategy) {
        this.drinks = new ArrayList<Double>();
        this.strategy = strategy;
    }

    public void add(double price, int quantity) {
        drinks.add(strategy.getActPrice(price * quantity));
    }

    // Payment of bill
    public void printBill() {
        double sum = 0;
        for (Double i : drinks) {
            sum += i;
        }
        System.out.println("Total due: " + sum);
        drinks.clear();
    }

    // Set Strategy
    public void setStrategy(BillingStrategy strategy) {
        this.strategy = strategy;
    }

}

interface BillingStrategy {
    public double getActPrice(double rawPrice);
}

// Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy {

    @Override
    public double getActPrice(double rawPrice) {
        return rawPrice;
    }

}

// Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy {

    @Override
    public double getActPrice(double rawPrice) {
        return rawPrice*0.5;
    }

}

댓글 없음:

댓글 쓰기