Skip to content

Instantly share code, notes, and snippets.

@jwChung
Last active May 7, 2022
Embed
What would you like to do?
Payment Example
using System;
using System.Collections.Generic;
namespace ClassLibrary3
{
public class Program
{
public static void Main(string[] args)
{
var service = new PaymentService(
new CompositeDiscountableFactory(
// new EventDiscountFactory(),
new NaverDiscountableFactory(),
new DanawaDiscountableFactory(),
new FancafeDiscountableFactory()));
service.Pay(100, "Naver");
service.Pay(100, "Danawa");
service.Pay(100, "Fancafe");
}
}
public class PaymentService
{
public PaymentService(IDiscountableFactory factory)
{
Factory = factory;
}
public IDiscountableFactory Factory { get; }
public void Pay(decimal amount, string discountName)
{
decimal payment = amount - Factory.Create(discountName).GetDiscountAmount(amount);
Console.WriteLine($"Paied {payment}.");
}
}
public interface IDiscountable
{
decimal GetDiscountAmount(decimal originalAmout);
}
public class NullDiscountPolicy : IDiscountable
{
private static NullDiscountPolicy instance = new NullDiscountPolicy();
private NullDiscountPolicy()
{
}
public static NullDiscountPolicy Instance
{
get { return NullDiscountPolicy.instance; }
}
public decimal GetDiscountAmount(decimal originalAmout)
{
throw new InvalidOperationException(
"This respresents the null-discount policy.");
}
}
public class RateDiscountPolicy : IDiscountable
{
public RateDiscountPolicy(decimal rate)
{
Rate = rate;
}
public decimal Rate { get; }
public decimal GetDiscountAmount(decimal originalAmout)
{
return originalAmout * Rate;
}
}
public class MaxDiscountPolicy : IDiscountable
{
public MaxDiscountPolicy(decimal maxAmount)
{
MaxAmount = maxAmount;
}
public decimal MaxAmount { get; }
public decimal GetDiscountAmount(decimal originalAmout)
{
return originalAmout < MaxAmount
? originalAmout
: MaxAmount;
}
}
public interface IDiscountableFactory
{
IDiscountable Create(string discountName);
}
public class CompositeDiscountableFactory : IDiscountableFactory
{
public CompositeDiscountableFactory(params IDiscountableFactory[] factories)
{
Factories = factories;
}
IEnumerable<IDiscountableFactory> Factories { get; }
public IDiscountable Create(string discountName)
{
foreach (IDiscountableFactory factory in Factories)
{
IDiscountable policy = factory.Create(discountName);
if (policy != NullDiscountPolicy.Instance)
return policy;
}
return NullDiscountPolicy.Instance;
}
}
public class NaverDiscountableFactory : IDiscountableFactory
{
public IDiscountable Create(string discountName)
{
return discountName == "Naver"
? (IDiscountable)new RateDiscountPolicy(0.1m)
: NullDiscountPolicy.Instance;
}
}
public class DanawaDiscountableFactory : IDiscountableFactory
{
public IDiscountable Create(string discountName)
{
return discountName == "Danawa"
? (IDiscountable)new RateDiscountPolicy(0.15m)
: NullDiscountPolicy.Instance;
}
}
public class FancafeDiscountableFactory : IDiscountableFactory
{
public IDiscountable Create(string discountName)
{
return discountName == "Fancafe"
? (IDiscountable)new MaxDiscountPolicy(50m)
: NullDiscountPolicy.Instance;
}
}
public class EventDiscountFactory : IDiscountableFactory
{
public IDiscountable Create(string discountName)
{
//DB에서 dicountName에 해당하는 할인율 적용
decimal rate;
if (TryGetDicountRate(discountName, out rate))
{
return new RateDiscountPolicy(rate);
}
return NullDiscountPolicy.Instance;
}
private bool TryGetDicountRate(string discountName, out decimal rate)
{
rate = 0.2m; // DB에서 할인율 가져오기
return true;
}
}
}
@redutan
Copy link

redutan commented Apr 5, 2016

코드 보고 잘 배우고 갑니다.
어떤 고민을 하셨는지 간접적으로 느껴지는 집니다.

@lja3723
Copy link

lja3723 commented May 7, 2022

코드 잘 보았습니다. 그런데 질문이 있습니다
코드에서 새로운 DiscountPolicy를 추가하려면 결국에는 Main 메서드가 있는 Program 클래스를 수정해야하는데, 그러면 결국 OCP가 또 위반이 되는게 아닌가 생각합니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment