I recently sorted out the company's specifications, and among them, "the number of parameters of a function should not exceed 4" was somewhat controversial during promotion. If the task can be completed, the fewer parameters, the better. This in itself is not controversial, but Doing so can cause difficulties when programming, and there is debate over whether it is worth it. I think it is worthwhile to do this to make it easier for people who use functions. As for the difficulties in programming, it is often because we are not familiar with some methods of reducing parameters. Here are a few summary for your reference:
1. Use structures to encapsulate parameters
Example: Add user
Original function body: AddUser (string userName, string password, string address, string phone, int age)
Refactor: add a User class:
class User
{
public string UserName { get; set; }
public string Password { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public int Age { get; set; }
}
Change AddUser to: AddUser(User user)
Problems: If the added class is not used elsewhere, we often feel that it is not worth it. At this time, we can consider using anonymous classes to encapsulate parameters.
2. Use attributes to replace parameters
If the AddUser method in 1 is placed in the User class, then the user parameters in the AddUser method can be omitted. Sometimes some attributes may be added in order to reduce the number of parameters in some methods. In object-oriented design, objects should be responsible for themselves, and responsibilities should be clearly defined. The reason why a method has too many parameters may be that the method is written in a place where it should not exist. The "information expert" model mentioned in the GRASP principle can reduce the number of parameters in many cases.
Example: Account transfer
Original function: Transfer (Account from, Account to, decimal money)
Refactoring:
code
public class TransferProcess
{
private Account From;
private Account To;
public TransferProcess(Account from, Account to)
{
this.From = from;
this.To = to;
}
public void Transfer(decimal money)
{
if (money<From.Money)
{
From.Money = From.Money - money;
To.Money = To.Money + money;
//update database
}
else
{
throw new Exception("Balance exceeded");
}
}
}
Note: The information expert pattern is the most basic principle of object-oriented design. When we design objects (classes), if a class has all the information needed to complete a certain responsibility, then this responsibility should be assigned to this class for implementation. At this time, this class is the information expert corresponding to this responsibility.
3. Use private functions
When calling a function, we often don’t need many interactive parameters, but when we provide parameters, we need to provide all the conditions. At this time, we can classify the functions, encapsulate the most complex functions as private, and expose the simple functions. Call these complex functions to complete the function. Let's take a look at the implementation of the TextBox method in mvc:
code
public static string TextBox(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> htmlAttributes) {
return InputHelper(htmlHelper, InputType.Text, name, value, (value == null) /* useViewData */, false /* isChecked */, true /* setId */, true /* isExplicitValue */, htmlAttributes);
}
private static string InputHelper(this HtmlHelper htmlHelper, InputType inputType, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, IDictionary<string, object> htmlAttributes) {
if (String.IsNullOrEmpty(name)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
}
TagBuilder tagBuilder = new TagBuilder("input");
... ...
But sometimes in order to give the caller maximum flexibility, we may also expose the most complex function overloading.
4. params keyword
Specifies that where the number of parameters is variable, the method parameter of the parameter is used.
usage:
code
static void Main(string[] args)
{
UseParams(1, 2, 3);
}
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
This method does not actually reduce the number of parameters, but only simplifies the function body.
5. Use anonymous classes to encapsulate parameters
Preparatory knowledge: Let’s take a look at RouteValueDictionary first
code
static void Main(string[] args)
{
RouteValueDictionary r = new RouteValueDictionary(new { id=1,name="lfm"});
foreach (var item in r)
{
Console.WriteLine("{0}:{1}", item.Key, item.Value);
}
//Console.WriteLine();
}
result:
id:1
name:lfm
RouteValueDictionary can store the attribute names and attribute values of instances into the dictionary.
Many places in mvc use this method to pass parameters.
For example: <%= Html.ActionLink("Details", "Details", new { id=item.id })%>
In the ActionLink method body, RouteValueDictionary is used to decompose the anonymous object and then assemble it onto the link.