简体   繁体   English

将数据传递给Method的更好方法是哪种

[英]Which is the better way of passing data to a Method

Let us say that we have 2 Classes Expense1 and Expense2 . 让我们说我们有2个Expense1Expense2 Which class implementation is preferred over the other, or which is considered closer to being object-oriented? 哪个类实现比另一个更受欢迎,或者被认为更接近于面向对象?

I always thought that doing Exp2.Calculate(1.5M,2) is more readable than exp1.Calculate() and using the properties of exp1 Class as the needed values for the calculate Method. 我一直认为做Exp2.Calculate(1.5M,2)exp1.Calculate()更具可读性,并使用exp1 Class的属性作为calculate方法的所需值。

Expense1 Expense1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class Expense1
{
    public decimal ExpenseValue { get; set; }
    public int NumberOfItems { get; set; }
    private decimal result;

    public decimal Result
    {
        get
        {
            return this.NumberOfItems * this.ExpenseValue;
        }
    }

    public void Calculate()
    {
        this.result = this.ExpenseValue * this.NumberOfItems;
    }

    public void expense1()
    {
        this.ExpenseValue = 0;
        this.NumberOfItems = 0;
    }
}

Expense2 Expense2

class Expense2
{
    public decimal Calculate(decimal expenseValue, int numberOfItems)
    {
        return expenseValue * numberOfItems;
    }
}

Implementation of both classes 两个类的实现

class Program
{
    static void Main(string[] args)
    {

        Expense1 exp1 = new Expense1();
        exp1.NumberOfItems = 2;
        exp1.ExpenseValue = 1.5M ;
        exp1.Calculate();
        Console.WriteLine("Expense1:" + exp1.Result.ToString());

        Expense2 exp2 = new Expense2();
        string result = string.Empty;
        result = exp2.Calculate(1.5M,2).ToString();
        Console.WriteLine("Expense2:" + result);
        Console.ReadKey();
    }
}

Expense2 is easier to read and understand what going on as it's evident from the call which parameters are used. Expense2更容易阅读和理解发生了什么,因为从调用中可以看出哪些参数被使用。

Expense1 could have various side effects as the caller might forget to set the variables used for calculating before he calls Calculate() . Expense1可能有各种副作用,因为调用者在调用Calculate()之前可能忘记设置用于计算的变量。

If you require access to the values that was used to calculate the result later, you can use something like this 如果您需要访问稍后用于计算结果的值,则可以使用类似的内容

public class Expense {
    public decimal ExpenseValue { get; private set; }
    public int NumberOfItems { get; private set; }
    public decimal Result { get; private set; }


    public decimal Calculate(decimal expenseValue, int numberOfItems) {
        ExpenseValue = expenseValue;
        NumberOfItems = numberOfItems;
        Result = ExpenseValue * NumberOfItems;

        return Result;
    }

    public Expense() {
        Calculate(0, 0);
    }
}

This will allow the internal state of Expense to stay consistent for the lifetime of the object, with the definition of how it's Calculated 这将允许Expense的内部状态在对象的生命周期内保持一致,并定义它的Calculated

Expense2.Calculate is deterministic (has the same result every time its called with the same parameters) and because it has no side effects (the parameters are served to it, rather than via properties) it is thread-safe too. Expense2.Calculate是确定性的(每次使用相同的参数调用时都具有相同的结果),并且因为它没有副作用(参数被提供给它,而不是通过属性),它也是线程安全的。 Lastly, it is simpler and easier to read. 最后,它更简单,更容易阅读。

Expense1 is a classic OOP train-wreck with non-thread safe state, and no guarantee that Result will return the result of a thread's invocation of Calculate . Expense1是一个经典的OOP训练 - 具有非线程安全状态的残骸,并且不保证Result将返回线程调用Calculate Further, it is long-winded and complex to read and maintain. 此外,阅读和维护冗长且复杂。

I'd favour Expense2 over Expense1 every time. 我每次都喜欢Expense2不是Expense1 The only thing I'd change would be to make it static as there's no gain to having to create an instance of Expense2 to call Calculate . 我唯一要做的就是让它变得静止,因为必须创建一个Expense2实例才能调用Calculate

I don't like Expense1 one bit. 我不喜欢Expense1一点。 I think properties with public get/set should generally be avoided since it provides no encapsulation. 我认为通常应该避免使用public get / set的属性,因为它不提供封装。 It's hardly even better than public fields (although it does give some room for guard clauses etc down the road). 它甚至不比公共场地更好(虽然它确实为后面的防守条款提供了一些空间)。

Worse than that, however, is the Calculate() method imo. 然而,更糟糕的是,Calculate()方法是imo。 It takes no arguments but it still changes the internal state of the object. 它不需要参数,但它仍然会改变对象的内部状态。 It is not clear how. 目前尚不清楚如何。 At the same time, the field it writes to, result , isn't being returned by the property Result , that property does the same calculation again (if you have to do calculations, generally prefer a method over a property). 同时,它写入的字段result不会被属性Result返回,该属性再次执行相同的计算(如果必须进行计算,通常更喜欢某个属性的方法)。

Finally, it is not necessary to initialize primitive types to their default value in the constructor, number types always get initialized to 0. 最后,没有必要在构造函数中将基元类型初始化为其默认值,数字类型始终初始化为0。

=== ===

Expense2 is better, it is more clear what is happening. 费用2更好,更清楚发生了什么。 Method takes two well-named arguments and give a reasonable result straight away. Method需要两个名称齐全的参数,并立即给出合理的结果。

If this method is the only use-case of the class, however, I would consider renaming it since it does not represent an expense, it represents something close to an expense calculator. 但是,如果这个方法是该类的唯一用例,我会考虑重命名它,因为它不代表费用,它代表了一个接近费用计算器的东西。

It all depends on what you want to do, but a rule of thumb is use properties when they are really linked to the object, and pass what use need as parameters when they are external to the object. 这一切都取决于你想做什么,但经验法则是当它们真正链接到对象时使用属性,并在它们在对象外部时传递使用需要的参数。

A simple example, consider having Person as a class, one of its properties is birthday, so in this case you should do this 一个简单的例子,考虑将Person作为一个类,它的一个属性是生日,所以在这种情况下你应该这样做

public class Person{
     public DateTime Birthday{get;set;}
     public int GetAge(){
          //some implementation
     }
}

another example, think of having a Cube object, and in this Cube object you have a method Intersect with another cube, in this case you should pass the second cube as parameter and not make it a property of Cube because it is something external. 另一个例子,想想有一个Cube对象,并且在这个Cube对象中你有一个方法与另一个立方体相交,在这种情况下你应该将第二个立方体作为参数传递,而不是使它成为Cube的属性,因为它是外部的东西。

public class Cube{
     public Cube Intersect(Cube other){
         //Do your logic here
     }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM