首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >支付系统迁移

支付系统迁移
EN

Code Review用户
提问于 2019-12-18 16:07:39
回答 1查看 242关注 0票数 5

GitHub

需要有一个软件设计,以支持从一个支付系统(E)逐步迁移到另一个支付系统(Stripe)。信用卡数据是存储在外部,所以我想使用这两个系统并行一段时间,不让所有用户重新输入信用卡数据。

下面是我目前在领域核心中拥有的内容:

代码语言:javascript
复制
public interface IMainPaymentAdapter : IPaymentAdapter
{
}

public interface IPaymentAdapter : IPaymentService
{
}

public interface IPaymentGateway : IPaymentService
{
}

public interface IPaymentService
{
    Task<BillingId> RegisterAsync(CreditCard card);
    Task ChargeAsync(BillingId id, decimal amount);
}

其思想是IPaymentService定义API形状,IPaymentAdaptor即将为每个正在使用的支付系统实现,IPaymentGateway基于BillingId向正确的适配器发出调用,并应该注入消费代码:

代码语言:javascript
复制
public abstract class BillingId
{
    public static BillingId Parse(string text)
    {
        var parts = text.Split('/');
        return (BillingId)Activator.CreateInstance(
            typeof(BillingId<>).MakeGenericType(Type.GetType(parts[0])),
            parts[1]);
    }

    protected BillingId(string value) => Value = value;
    public string Value { get; }
    public abstract Type Adapter { get; }
    public override string ToString() => 
        $"{Adapter.AssemblyQualifiedName}/{Value}";
}

public class BillingId<TAdapter> : BillingId 
    where TAdapter : IPaymentAdapter
{
    public BillingId(string value) : base(value) { }
    public override Type Adapter => typeof(TAdapter);
}

我的网关看起来是这样的--请注意,卡片注册呼叫总是被分派到当前的IMainPaymentAdaptor实现,而其他所有东西都被发送到最初提供计费id的适配器:

代码语言:javascript
复制
[Service]
public class PaymentGateway : IPaymentGateway
{
    public PaymentGateway(IServiceProvider provider) => Provider = provider;
    IServiceProvider Provider { get; }

    public async Task<BillingId> RegisterAsync(CreditCard card) =>
        await Adapter().RegisterAsync(card);

    public async Task ChargeAsync(BillingId id, decimal amount) =>
        await Adapter(id).ChargeAsync(id, amount); 

    IPaymentAdapter Adapter() => Adapter(typeof(IMainPaymentAdapter));
    IPaymentAdapter Adapter(BillingId id) => Adapter(id.Adapter);
    IPaymentAdapter Adapter(Type type) => 
        (IPaymentAdapter)Provider.GetService(type);
}

下面是Stripe适配器程序集中的内容:

代码语言:javascript
复制
public interface IStripeAdapter : IMainPaymentAdapter
{
}

[Service]
public class StripeAdapter : IStripeAdapter
{
    StripeClient Client { get; } = new StripeClient();

    public async Task<BillingId> RegisterAsync(CreditCard card) =>
        new BillingId<IStripeAdapter>(await Client.RegisterAsync(card));

    public async Task ChargeAsync(BillingId id, decimal amount) =>
        await Client.Charge(id.Value, amount);
}

请注意,E-xact适配器(退役适配器)应该基于IPaymentAdaptor,而不是IMainPaymentAdapter

代码语言:javascript
复制
public interface IEXactAdapter : IPaymentAdapter
{
}

你对这种设计方法有什么看法?看上去够干净吗?

EN

回答 1

Code Review用户

发布于 2019-12-19 19:54:19

这是一个简化的版本,感谢这个回答

代码语言:javascript
复制
public interface IMainPaymentProvider : IPaymentProvider
{
}

public interface IPaymentProvider : IPaymentService
{
    string Name { get; }
}

public interface IPaymentGateway : IPaymentService
{
}

public interface IPaymentService
{
    Task<BillingId> RegisterAsync(CreditCard card);
    Task ChargeAsync(BillingId id, decimal amount);
}

其中:

代码语言:javascript
复制
[TypeConverter(typeof(BillingIdTypeConverter))]
[JsonConverter(typeof(BillingIdJsonConverter))]
public class BillingId
{
    public static BillingId Parse(string text) =>
        IsNullOrWhiteSpace(text) ? null :
        text.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries) is string[] p && p.Length == 2
            ? new BillingId(p[0], p[1]) 
            : throw new FormatException();

    public BillingId(string provider, string value) => 
        (Provider, Value) = (provider, value);

    public string Provider { get; }
    public string Value { get; }

    public override string ToString() => 
        $"{Provider}:{Value}";
}

因此,支付网关看起来像是:

代码语言:javascript
复制
[Service]
public class PaymentGateway : IPaymentGateway
{
    public PaymentGateway(IMainPaymentProvider mainProvider, params IPaymentProvider[] providers) => 
        (MainProvider, Providers) = 
        (mainProvider, providers.ToDictionary(p => p.Name));

    IPaymentProvider MainProvider { get; }
    IReadOnlyDictionary<string, IPaymentProvider> Providers { get; }

    public async Task<BillingId> RegisterAsync(CreditCard card) =>
        await MainProvider.RegisterAsync(card);

    public async Task ChargeAsync(BillingId id, decimal amount) =>
        await Providers[id.Provider].ChargeAsync(id, amount); 
}

一个示例提供者可以是:

代码语言:javascript
复制
public interface IStripeProvider : IMainPaymentProvider
{
}

[Service]
public class StripeProvider : IStripeProvider
{
    StripeClient Client { get; } = new StripeClient();

    public string Name => "Stripe";

    public async Task<BillingId> RegisterAsync(CreditCard card) =>
        new BillingId(Name, await Client.RegisterAsync(card));

    public async Task ChargeAsync(BillingId id, decimal amount) =>
        await Client.Charge(id.Value, amount);
}
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/234271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档