2017-11-10 8 views
3

나는 좋은 것처럼 보이는 문제를 처리하기위한 좋은 방법을 찾으려고 애 쓰고 있습니다.Creational Patterns suggestive

내 전체 모델은 가격 책정 전략의 개념에 의존합니다. 이 전략은 규칙에 따라 특정 가격을 계산합니다. 규칙은 어떻게 현재 그들 각각의 자체 IStrategy

public abstract class RuledBasedPricingStrategy : IPricingStrategy 
{ 
    public abstract string FriendlyName { get; } 
    protected abstract ICollection<IPricingRule> Rules { get; } 

    protected Booking Booking { get; } 
    protected Resource Resource { get; } 
    protected TecTacClient Client { get; } 

    protected RuledBasedPricingStrategy(Booking booking, Resource resource, TecTacClient client) 
    { 
     // Just checking and assigning values(...) 
    } 

    public abstract bool IsEligible(); 

    public Pricing Build() 
    { 
     var strategy = new Pricing(FriendlyName, Resource.CurrencyCode); 
     foreach (var r in Rules.OrderByDescending(x => x.Priority)) 
      r.Apply(strategy, Booking, Resource, Client); 
     return strategy; 
    } 
} 

public class RegularPricingCalculatorFactory : RuledBasedPricingStrategy 
{ 
    public override string FriendlyName => "Regular Pricing"; 

    protected override ICollection<IPricingRule> Rules => new List<IPricingRule> 
    { 
     new OfficeHourPricingRule(), 
     // Non Office Hours 
     new OnePercentSurchagePricingRule() 
    }; 

    public override bool IsEligible() => (...) 

    public RegularPricingCalculatorFactory(Booking booking, Resource resource, TecTacClient client) 
     : base(booking, resource, client) 
    { } 
} 

public class HalfdayPricingStrategy : RuledBasedPricingStrategy 
{ 
    public override string FriendlyName => "Half day Pricing"; 

    protected override ICollection<IPricingRule> Rules => new List<IPricingRule> 
    { 
     new HalfDayPricingRule(), 
     new OfficeHourPricingRule(), 
     // Non Office Hours 
    }; 

    public override bool IsEligible() => (...) 

    public HalfdayPricingStrategy(Booking booking, Resource resource, TecTacClient client) 
     : base(booking, resource, client) { } 
} 
를 구현 RuledBasedPricingStrategy에서 상속, 6 개 전략이 주어진 시간 범위에 대한 가격 (자정 비용 돈의 양이 오전 8 ...)

을 계산

IRule은 간단한 인터페이스입니다. 규칙 매개 변수로 가격을 받아 필요한만큼의 가격 단계를 추가합니다 : 등등 (...)

public class Pricing 
{ 
    public string Name { get; } 
    public string CurrencyCode { get; } 
    private readonly List<PricingStep> _steps; 
    public ICollection<PricingStep> Steps => _steps.AsReadOnly(); 
    public decimal TotalPrice => Steps.Sum(x => x.Price); 
} 

을 그리고 아래 그림과 같이

public interface IPricingRule 
{ 
    int Priority { get; } 
    void Apply(Pricing pricing, Booking booking, Resource resource, TecTacClient client); 
} 

가격 책정은 간단한 클래스입니다

나는 이러한 모든 전략을 인스턴스화하는 좋은 방법을 찾고 있습니다. 당신이 알아 차렸 듯이 예약, 자원 및 클라이언트 객체를 인수로 사용합니다. 필자의 첫 번째 요점은 이러한 인수를 두 번 전달하지 않는 것이 었습니다 (IsEligible 및 Build). 올바른 방법이 될 것 같지 않습니다

public IEnumerable<IPricingStrategy> Find(Booking booking, Resource resource, TecTacClient client) 
     => _strategiesType 
      .Select(t => Activator.CreateInstance(t, booking, resource, client)) 
      .OfType<IPricingStrategy>(); 

: 그러나 나는 모든 전략 유형을 알고하는 "공장"을 구축하고 그들에게 나는 새로운 요청을받을 때마다 인스턴스화해야합니다. 전략은 일단 인스턴스화 된 다음 전략을 계산하기 위해 재사용되어야합니다. 그러나 나는 그런 경우를 끝낼 것입니다.

foreach(var s in strategies) 
    if (s.IsEligible(booking, resource, client)) 
     yield return s.Build(booking, resource, client); 

이 코드를 단순화/정리하는 데 사용할 수있는 패턴은 무엇입니까? 당신이 언급했듯이

들으 셉은

답변

0

, 생성자로 매개 변수를 전달하는 것은 당신이 당신의 IPricingStrategies 때마다 이러한 매개 변수 중 하나가 변경 각각의 새로운 인스턴스를 확인해야합니다 것을 의미한다.

그러나 은 전략의 두 가지 방법에 동일한 매개 변수 집합을 전달하려고하지 않습니다.

처음 두 가지 방법이 분리 된 이유가 있습니까? 호출자는 Build을 호출할지 여부를 결정하는 것을 제외하고는 결코 IsEligible에 전화하기를 원할 것입니다. 우리는 전략으로 그 결정을 이동하고 (복합) 결과를 반환 할 수 있습니다 : -

// You can make this guy more sophisticated by building a proper 
// option type if you like, but this is good enough as an example. 
class PricingStrategyResult 
{ 
    public bool IsEligible { get; set; } 
    public Pricing Pricing { get; set; } 
} 

interface IPricingStrategy 
{ 
    // Your caller passes the parameters and receives both values 
    // at once. 
    PricingStrategyResult Build(
    Booking booking, 
    Resource resource, 
    TecTacClient client) 
} 

// But you can still split the logic up at the implementation 
// level if you need to. 
public abstract class RuledBasedPricingStrategy : IPricingStrategy 
{ 
    protected abstract bool IsEligible(); 

    public PricingStrategyResult Build(
    Booking booking, 
    Resource resource, 
    TecTacClient client) 
    { 
    if (!this.IsEligible) 
    { 
     return new PricingStrategyResult() 
     { 
     IsEligible = false 
     }; 
    } 

    var pricing = new Pricing(FriendlyName, Resource.CurrencyCode); 

    foreach (var r in Rules.OrderByDescending(x => x.Priority)) 
    { 
     r.Apply(pricing, booking, resource, client); 
    } 

    return new PricingStrategyResult() 
    { 
     IsEligible = true, 
     Pricing = pricing 
    }; 
    } 
} 

그런 다음 당신이 원하는 전화 : -

results = strategies.Build(booking, resource, client) 
        .Where(x => x.IsEligible) 
        .Select(x => x.Pricing); 
+0

나는 그것을 놓친 오는 방법! 그건 분명해. – Seb