方法重载。你能过度使用它吗?

2022-09-01 02:52:37

在定义多个使用不同筛选器返回相同形状数据的方法时,更好的做法是什么?显式方法名称还是重载方法?

例如。如果我有一些产品,并且我正在从数据库中提取

显式方式:

public List<Product> GetProduct(int productId) {    // return a List    }
public List<Product> GetProductByCategory(Category category) {    // return a List    }
public List<Product> GetProductByName(string Name ) {    // return a List    }

过载方式:

public List<Product> GetProducts() {    // return a List of all products    }
public List<Product> GetProducts(Category category) { // return a List by Category }
public List<Product> GetProducts(string searchString ) { // return a List by search string }

我意识到你可能会遇到类似签名的问题,但是如果你传递对象而不是基类型(字符串,int,char,DateTime等),这将不是一个问题。所以。。。为了清楚起见,重载一个方法来减少方法的数量是一个好主意,还是应该以不同方式筛选数据的每个方法都有不同的方法名称


答案 1

是的,重载很容易被过度使用。

我发现,确定重载是否值得的关键是考虑受众 - 不是编译器,而是维护程序员,他们将在几周/几个月/几年内出现,并且必须了解代码试图实现的目标。

像GetProducts()这样的简单方法名称是清晰易懂的,但它确实留下了很多未说的。

在许多情况下,如果传递给 GetProducts() 的参数命名良好,维护人员将能够计算出重载的作用 - 但这依赖于在使用点的良好命名规则,这是无法强制执行的。您可以强制执行的是它们所调用的方法的名称。

我遵循的准则是,如果方法可互换,则仅重载它们 - 如果它们执行相同的操作。这样,我就不介意我的类的使用者调用哪个版本,因为它们是等效的。

为了说明这一点,我很乐意对 DeleteFile() 方法使用重载:

void DeleteFile(string filePath);
void DeleteFile(FileInfo file);
void DeleteFile(DirectoryInfo directory, string fileName);

但是,对于您的示例,我将使用单独的名称:

public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByName(string Name ) {...}

拥有全名使代码对维护人员(很可能是我)更加明确。它避免了签名冲突的问题:

// No collisions, even though both methods take int parameters
public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesByDepartment(int departmentId);

还有机会为每个目的引入重载:

// Examples for GetEmployees

public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesBySupervisor(Supervisor supervisor);
public IList<Employee> GetEmployeesBySupervisor(Person supervisor);

public IList<Employee> GetEmployeesByDepartment(int departmentId);
public IList<Employee> GetEmployeesByDepartment(Department department);

// Examples for GetProduct

public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductById(params int[] productId) {...}

public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByCategory(IEnumerable<Category> category) {...}
public IList<Product> GetProductByCategory(params Category[] category) {...}

代码的读取量比编写的要多得多 - 即使您在最初签入到源代码管理后再也回不来过代码,在编写下面的代码时,您仍然会将这行代码读取几十次。

最后,除非你正在编写一次性代码,否则你需要允许其他人从其他语言调用你的代码。似乎大多数业务系统最终都停留在生产中,远远超过了它们的使用日期。可能是在 2016 年使用你的类的代码最终被写成 VB.NET、C# 6.0、F# 或尚未发明的全新内容。可能是该语言不支持重载。


答案 2

据我所知,你不会有更少的方法,只会有更少的名字。我通常更喜欢重载方法系统的命名,但我认为只要你很好地注释和记录你的代码(在任何一种情况下你都应该这样做),它真的不会有太大的区别。