2013-04-19 3 views
2

안녕하세요, 코드의 일부를 리퍼 팩터로 열거 나 닫힌 원칙에 부합하도록 지정했습니다. 두 가지 방법으로 전략 패턴을 적용했지만 나는 어떻게해야할지 모르겠다. 이 방법은이 방법이 수정을 위해 닫혀 있지 서있는 class.As의 방법을 사용하여 객체를 initialezes이 경우메서드에서 열기/닫기 원칙 적용

public ProductPriceCalculator(Product product) 
{ 
    this.product = product; 
    buyerStrategy = new BuyerStrategy(); 
    discountStrategy = new DiscountStrategy(); 
} 

public Price CalculatePrice() 
{ 
    price = new Price(); 

    decimal productPrice = product.BasePrice + 
          (product.BasePrice * product.Addition); 
    decimal TVA = CalculateTVA(); 
    price.ProductPrice = productPrice*TVA; 
    decimal discount = CalculateDiscount(price.ProductPrice); 
    price.Discount = price.ProductPrice * discount; 
    price.ProductPriceWithDiscount = price.ProductPrice - price.Discount; 
    price.TransportPrice = product.Transport.GetTransportPrice(); 
    price.TotalPrice = price.ProductPriceWithDiscount + price.TransportPrice; 

    return price; 
} 

어떤 점에서 나는 또 다른 속성을 추가해야하는 경우 내가해야 할 가격 때문에 초기화하려면 여기로 돌아 오십시오.

어떻게이 코드를 올바르게 구성 할 수 있습니까?

+0

나는 귀하의 우려를 정말로 이해하지 못합니다. 가격 클래스가 다른 속성을 얻는 경우 Price 생성자에서 초기화해야합니다. 계산 된 값이 필요한 경우 계산을 수정해야합니다. 하지만 어딘가에 코드가 있어야하고 코드를 수정해야합니다. O/C 원칙은 현재 가격 계산기를 새로운 가격 계산기로 교체 할 가능성이 있으므로 아마도이 제품에서 파생 된 것일 수 있습니다. 이 문서에서 제대로 파생 될 수 있는지 확인하십시오. – nvoigt

+0

@noveigt 자세한 내용은 파생 된 계산기를 투명하게 사용할 수있는 가능성이 [Liskov Substitution Principle] (http://en.wikipedia.org/wiki/Liskov_substitution_principle)과 더 관련이 있다고 말할 수 있습니다. 열기/닫기 원칙은 원래 Calculator 클래스의 코드를 수정하지 않고도 상속을 통해 계산기 기능을 확장 할 수 있다는 사실에 더 가깝습니다. – Marshall777

답변

5

한 가지 가능한 솔루션은 다음과 같은있다 :

public class ProductPriceCalculator 
{ 
    private readonly Product _product; 
    private readonly BuyerStrategy _buyerStrategy; 
    private readonly DiscountStrategy _discountStrategy; 
    private readonly Price _price; 

    public ProductPriceCalculator(Product product,BuyerStrategy buyerStrategy,DiscountStrategy discountStrategy,Price price) 
    { 
     _product = product; 
     _buyerStrategy = buyerStrategy; 
     _discountStrategy = discountStrategy; 
     _price = price; 
    } 

    public Price CalculatePrice() 
    { 
     decimal productPrice = _product.BasePrice + (_product.BasePrice * _product.Addition); 
     decimal TVA = CalculateTVA(); 
     decimal discount = CalculateDiscount(productPrice * TVA); 
     decimal transportPrice = _product.Transport.GetTransportPrice(); 

     return _price.CalculatePrice(productPrice*TVA,discount,transportPrice); 
    } 

    ... 

} 

public class Price 
{ 
    ... 

    public virtual Price CalculatePrice(decimal productPrice, decimal discount, decimal transportPrice) 
    { 
     Price price = new Price(); 

     price.ProductPrice = productPrice; 
     price.Discount = ProductPrice * discount; 
     price.ProductPriceWithDiscount = ProductPrice - Discount; 
     price.TransportPrice = transportPrice; 
     price.TotalPrice = ProductPriceWithDiscount + TransportPrice; 

     return price; 
    } 

    ... 

} 

생성자에 종속 (예 : buyerStrategy, discountStrategy, price)를 넣어보다 것은 그들을 생성 한 후 다른 사람이 아니라 IoC 컨테이너 또는 무언가를 통해 그들을 채우기 위해 좋다 생성자 자체에서. _price 필드를 소개 한 후 채우기 가격의 속성을 Price 클래스 자체에 위임 할 수 있습니다. 메서드 Price.CalculatePricePrice 클래스의 패브릭 메서드로 호출 할 수 있습니다.

+1

+1 나는 똑같이 할 것입니다. 다른 인터페이스 만 만들면됩니다. 그것은 테스트와 확장성에 도움이됩니다. –

+0

일 수 있습니다. 인터페이스 대 상속은 잘 알려진 질문입니다. 그러나 여기에서 요점이 아니다. – bbonch

+0

이 솔루션을 사용하면 Price 클래스에 추가 속성을 어떻게 추가 할 것입니까? – Bertie

1

비트는 주변 코드에 대해 조금 더 알지 못해도 말하기가 어렵지만 어쩌면 Decorator Pattern이이를 해결할 수 있다고 생각했을까요?! 아마도 이러한 라인을 따라 뭔가 인스턴스에 그래서 : 당신이 계산을 변경할 필요가 없기 때문에 새로운 속성을 추가하고 여전히 폐쇄 원칙을 지원하기로

public abstract class BaseProduct 
{ 
    public decimal BasePrice { get; set; } 
    public decimal Addition { get; set; } 
    public Transport Transport { get; set; } 

    public abstract void CalculatePrice(decimal discount); 
} 

public class Product : BaseProduct 
{ 
    public BasePrice Price { get; set; } 

    public Product(BasePrice price) 
    { 
     this.Price = price; 
    } 

    public override void CalculatePrice(decimal discount) 
    { 
     this.Price.CalculatePrice(this.BasePrice, this.Addition, discount); 
    } 
} 

public abstract class BasePrice 
{ 
    public abstract void CalculatePrice(decimal basePrice, decimal additional, decimal discount); 
} 

public class Price : BasePrice 
{ 
    public decimal ProductPrice { get; set; } 
    public decimal Discount { get; set; } 
    public decimal ProductPriceWithDiscount { get; set; } 
    public decimal TransportPrice { get; set; } 
    public decimal TotalPrice { get; set; } 

    public override void CalculatePrice(decimal basePrice, decimal additional, decimal discount) 
    { 
     this.ProductPrice = basePrice + (basePrice * additional); 
     this.Discount = this.ProductPrice * discount; 
     this.ProductPriceWithDiscount = this.ProductPrice - this.Discount; 
     this.TotalPrice = this.ProductPriceWithDiscount + this.TransportPrice; 
    } 
} 

이 방법을 사용하면 BasePrice의 새로운 고정 구현을 만들 수 있습니다 원래 클래스의 논리. 변경 될 때 새로운 구체적인 구현을 추가하기 만하면됩니다. 그냥 명확히하기 위해 제품이 구성 요소이고 가격이 장식입니다.

바라건대 내가 그 의견을 열어 주었으면합니다! 그리고 똑같이, 그것이 도움이되기를 바랍니다 !! :)