2019년 5월 20일 월요일

전략 패턴(많은 if문 피하기)

거리 환산 프로그램을 다시 생각해본다.

예를 들어, 야드에서 피트로 변환하는 방법을 생각해보겠습니다.
야드를 그냥 피트로 변환할 수도있지만 일단 야드에서 미터로 변환하고 나서 미터에서 피트로 변환해도 동일한 결과가 나옵니다.
인치에서 피트로 변환할 경우에도 인치에서 미터로 변환하고 그것을 피트로 변환해도 결과를 구할 수 있습니다.
다시 말해 어떤 변환이라도 일단 미터로 변환한 후에 처음에 목표로 정한 단위로 변환할 수 있습니다.




Convert에 공통되는 메서드와 속성을 정의한다.

public abstract class ConvertBase {
    // 미터와의 비율(이 비율을 곱하면 미터로 변환된다)
    protected abstract double Ratio { get; set; }

    // 거리의 단위 이름(예를 들어 미터 , 피트 등)
    public abstract string UnitName { get; }

    // 미터로부터 변환
    public double FromMeter(double meter)
    {
        return meter / Ratio;
    }

    // 미터로 변환
    public double ToMeter(double feet)
    {
        return feet * Ratio;
    }
}

FromMeter, ToMeter라는 두 개의 메서드는 모든 서브 클래스에서 공통으로 이용하는 메서드입니다.
이러한 구체적인 처리 코드가 있기 때문에 IConverter라는 인터페이스가 아닌 클래스로 지정한것입니다.

그리고 ConverterBase 클래스의 인스턴스를 직접 생성하지는 않을 것이므로 abstract를 붙여 추상클래스로 지정했습니다. ConverterBase 클래스에서 Ratio라는 속성이 미터와의 비율을 나타내는데 이 클래스에 구체적인 값을 넣어둘 수 없으므로 abstract로 지정해서
서브 클래스에서 반드시 구현하게 합니다.
UnitName 속성도 마찬가지로 서브 클래스에서 내용을 정의할 것이므로 abstract로 지정했습니다.

FromMeter 메서드와 ToMeter 메서드는 Ratio의 값이 정해지면 어떤 서브 클래스에서도
동일한 로직을 통해 계산할 수 있으므로 상속하는 부모인 ConverterBase 클래스에서
내용을 정의했습니다.

Converter의 구상 클래스 정의



public class MeterConverter : ConvertBase{
    protected override double Ratio
    {
        get { return 1; }
    }
    public override string UnitName
    {
        get { return "미터"; }
    }
}
public class FeetConverter : ConvertBase {
    protected override double Ratio
    {
        get { return 0.3048; }
    }
    public override string UnitName
    {
        get { return "피트"; }
    }
}
public class InchConverter : ConvertBase {
    protected override double Ratio
    {
        get{ return 0.0254; }
    }
    public override string UnitName
    {
        get{ return "인치"; }
    }
}
public class YardConverter : ConvertBase {
    protected override double Ratio
    {
        get{ return 0.9144; }
    }
    public override string UnitName
    {
        get{ return "야드"; }
    }
}






네 개의 서브 클래스에서는 상속해준 부모 클래스에 있는 abstract 멤버를 오버라이드했습니다.
각 클래스의 차이를 일목요연하게 볼 수 있습니다. MeterConverter 클래스도 정의돼 있습니다. 이 클래스를 정의해두면 '피트에서 미터로 그리고 미터에서 인치로' 같은 방식으로 변환할 수 있습니다.

거리를 단위 변환하는 클래스를 정의한다.

각 Converter 클래스를 정의했으므로 이번에는 이 응용 프로그램이 본래 가져야 할 기능인'거리를 단위 변환하는' 클래스를 정의하겠습니다. 이 클래스의 이름은 DistanceConverter라고 지정합니다.

public class DistanceConverter {
    public ConvertBase From { get; set; }
    public ConvertBase To { get; set; }

    public DistanceConverter(ConvertBase from, ConvertBase to)
    {

        From = from;
        To = to;
    }

    public double Convert(double value)
    {
        var meter = From.ToMeter(value);
        return To.FromMeter(meter);
    }
}








댓글 없음:

댓글 쓰기

git rejected error(feat. cherry-pick)

 문제 아무 생각 없이 pull을 받지않고 로컬에서 작업! 커밋, 푸시 진행을 해버렷다. push에선 remote와 다르니 당연히 pull을 진행해라고 하지만 로컬에서 작업한 내용을 백업하지 않고 진행하기에는 부담스럽다(로컬작업 유실 가능성) 해결하려...