使用结构作为方法的输入是否有缺点?

The*_*ook 5 .net c# oop

我不是专家,但我想知道我的逻辑是否存在缺陷.我很确定不会花很长时间才能指出它是否如此!

为什么不简单地将结构作为单个输入参数,而不是在常用方法上定义几个参数?如果单独定义每个参数并添加另一个参数或删除一个参数,则需要对调用该方法的每段代码进行维护.如果使用了一个结构,那么肯定没有任何调用代码会破坏吗?如果将来某些代码需要额外的参数但遗留代码没有,我可以将该参数添加到现有列表中,遗留代码仍然无需担心.

举个例子:我正在寻找一家公司,那里有多个网站/项目(从我的原始帖子中澄清,其中说"产品"并且可能被误解为物理产品)需要与支付网关连接.根据客户位置,最多可以调用五个不同的支付网关来处理客户付款.

目前,这些多个产品中的每一个都有自己的支付处理实现,完成了从网关检查返回的参数.我发现这个令人困惑,而且是完全错误的,尽管目前还没有时间或资源从头开始重写所有内容,但我认为相对快速的解决办法是创建一个新的"支付"类项目,该项目已定义一组参数.

就我而言,前端应该只做一些简单的事情,如调用"在国家z中以货币y支付x"的方法,并期望成功/失败标志和可选消息澄清任何失败作为回报.这样,公司拥有的每个产品都将共享相同的支付处理.

现在参数明智,目前输入的要求只是金额,货币和国家(不,你不能总是在有人建议之前根据客户位置推断货币!).对于返回,它只是布尔成功/失败以及解释失败原因的消息.然而,将来可能需要额外的参数 - 无论是in还是out - 并且不想破坏现有的方法调用,简单地使用简单的结构似乎是明智的,例如:

 struct inParams
 {
     public decimal amount;
     public string currency;
     public string country;
 };

 struct outParams
 {
     public bool success;
     public string message;
 };

    public outParams makePayment(inParams ip)
    {
        //...code goes here
    }
Run Code Online (Sandbox Code Playgroud)

这是一个代码方面的"坏事"还是可以接受的做法?如果有人认为单独在方法签名中定义参数会更好,那么请您解释一下为什么这比使用简单结构的建议更好吗?


回应"oɔɯǝɹ"

我并没有真正看到你提出的问题是严重的.

例如,示例调用将类似于:

       PaymentProcessor pp = new PaymentProcessor();
       ppInParams ppIn = new ppInParams();
       ppIn.amount = 100;
       ppIn.currency = "USD";
       ppIn.country = "USA";

       ppOutParams ppOut = pp.makePayment(ppIn);
       if (!ppOut.success)
       {
           //check error message, handle error, display message
       }
       else
       {
           //display confirmation message to user, update account log
       }
Run Code Online (Sandbox Code Playgroud)

你的观点:This leads to not very discoverable code面对如上所示的这种简单性,很难证明这一点,当然可以吗?

Users need to add extra boiler plate code just to instantiate your parameter struct. - 好吧,是的,但是为每个参数添加一行代码并不是一个主要的问题,是吗?

You will need to manage heaps of parameter structs. Two for every method. -How are you even going to name them? -In case you're thinming, I know, I'll just reuse them, then you've made your problem worse. Whats gonna happen when a single method using a struct need another parameter?

我也没有在这里看到问题.我有一个"paymentProcessor"类,其中我有"ppInParams"和"ppOutParams",它们包含在类本身中 - 对我来说,这是一个非常合理的地方,可以将它们直接与该类相关联.

你的最后一点:And in particular, your return type struct smells funny to me. Do you expect that every caller will inspect the boolean result? And what should i do with the message? Log it? show it? Have you not heard of structured exception handling?对我来说似乎很奇怪,我不明白你想要做的一点.百万分之一是我希望每个调用者检查布尔响应,因为这是告诉他们付款是否成功的原因!这就是确实如此简化通话的重点吗?由于错误处理根据哪个网站称为"makepayment"方法而有所不同,因此我再次在调用代码中处理错误是完全合理的.

Mic*_*ine 3

产品不应包含付款处理。支付处理不描述属性或操作,它描述上的Product操作。您可能需要一个可以松散地基于您的结构的对象: ProductPaymentinParams

class Payment {
    public decimal Amount { get; set; }
    public string Currency { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Country物业很有趣。如果知道订单的下达位置很重要,则订单来自单个位置,因此Country应该属于Order。但是,如果了解每笔付款来自哪个国家/地区很重要,那么Country应该属于Payment。那取决于你。我包含CountryOrder.

您还需要一个Order对象来对Payment和进行分组Products。请注意,该Order对象接受接口IPaymentProcessor作为构造函数参数。您可以通过将接口的不同实现传递IPaymentProcessorOrder对象来实现不同的支付处理行为。您可以应用业务逻辑来确定应将哪个具体实现发送给Order构造函数。重要的是您永远不需要改变您的OrderPayment类来改变支付处理行为。

class Order {
    public string Country { get; set; }
    public ICollection<Payment> Payments { get; set; }
    public ICollection<Product> Products { get; set; }
    private IPaymentProcessor paymentProcessor;

    public Order(IPaymentProcessor paymentProcessor) {
        this.paymentProcessor = paymentProcessor;
    }

    void MakePayment(Payment payment) {
        this.paymentProcessor.ProcessPayment(payment);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您永远不会接受订单上的多次付款,您可以将 更改ICollection<Payment> PaymentsPayment Payment

IPaymentProcessor接口:

interface IPaymentProcessor {
    void ProcessPayment(Payment payment);
}
Run Code Online (Sandbox Code Playgroud)

请记住,结构是值类型,当它们作为参数传递给方法时将被复制。类是引用类型,并且只有引用(基于计算机字大小的 32 或 64 位值)按值传递给方法。在这种情况下,类似乎更好,特别是当您预计对象会增长时。

评论后更新:

嗯,这肯定改变了我阅读你的问题的方式!我认为大部分答案仍然适用,所以我将保留它。使用上面的逻辑,我将实现一个OrderProcessor服务,该服务将接受Order对象并调用它们的ProcessPayment方法(以及所需的任何其他逻辑)。IPaymentProcessor您仍然根据系统(订单来源)的规则注入接口。或者,如果订单流程的大部分内容相似,则考虑创建IPaymentProcessor一个基类PaymentProcessor,您可以在需要时覆盖基类中的特定行为。有很多方法可以实现这一点,但我试图传达的主要思想是,这是多态性的一个很好的案例,这只是一个如何使用该原则构建基本架构的示例。