这是将数据传递给方法的更好方式
本文关键字:方法 更好 方式 数据 | 更新日期: 2023-09-27 18:05:22
设我们有两个类Expense1
和Expense2
。哪个类实现比另一个更受欢迎,或者哪个被认为更接近面向对象?
我一直认为做Exp2.Calculate(1.5M,2)
比exp1.Calculate()
和使用exp1类的属性作为计算方法的所需值。
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
class Expense2
{
public decimal Calculate(decimal expenseValue, int numberOfItems)
{
return expenseValue * numberOfItems;
}
}
两个类的实现
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
更容易阅读和理解发生了什么,因为从调用中可以看出使用了哪些参数。
Expense1
可能有各种副作用,因为调用者可能在调用Calculate()
之前忘记设置用于计算的变量。
如果稍后需要访问用于计算结果的值,可以使用如下内容
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);
}
}
这将允许Expense
的内部状态与Calculated
Expense2.Calculate
是确定性的(每次使用相同的参数调用时都有相同的结果),并且因为它没有副作用(参数是提供给它的,而不是通过属性),所以它也是线程安全的。最后,它更简单,更容易阅读。
Expense1
是一个典型的非线程安全状态的OOP问题,并且不能保证Result
将返回线程调用Calculate
的结果。而且,它冗长,阅读和维护起来很复杂。
每次我都更喜欢Expense2
而不是Expense1
。我唯一要改变的是使它成为静态的,因为没有必要创建Expense2
的实例来调用Calculate
。
我一点也不喜欢Expense1我认为通常应该避免使用public get/set属性,因为它没有提供封装。它甚至很难比公共字段更好(尽管它确实给了一些保护条款等空间)。
然而,在我看来,比这更糟糕的是Calculate()方法。它不带参数,但仍然会改变对象的内部状态。目前尚不清楚是如何做到的。同时,它写入的字段result
没有由属性Result
返回,该属性再次进行相同的计算(如果必须进行计算,通常更倾向于使用方法而不是属性)。
最后,没有必要在构造函数中将基本类型初始化为默认值,数字类型总是初始化为0。
= = =
Expense2更好,它更清楚发生了什么。方法接受两个命名良好的参数,并直接给出合理的结果。
如果这个方法是该类的唯一用例,那么我将考虑重命名它,因为它不表示费用,它表示的是接近于费用计算器的东西。
这完全取决于你想做什么,但经验法则是,当属性真正与对象相关联时使用属性,当属性位于对象外部时,将需要的属性作为参数传递。
一个简单的例子,考虑将Person作为一个类,它的一个属性是birthday,所以在这种情况下你应该这样做
public class Person{
public DateTime Birthday{get;set;}
public int GetAge(){
//some implementation
}
}
另一个例子,考虑有一个立方体对象,在这个立方体对象中,你有一个与另一个立方体相交的方法,在这种情况下,你应该将第二个立方体作为参数传递,而不是使其成为立方体的属性,因为它是外部的东西。
public class Cube{
public Cube Intersect(Cube other){
//Do your logic here
}
}