Return to the General Directory
This little program record
- Replace Parameter with Explicit Methods (replacing parameters with explicit functions)
- Preserve Whole Object
6 Replace Parameter with Explicit Methods (replacing parameters with explicit functions)
outline
You have a function that takes different actions depending entirely on the value of the parameter. For each possible value of the parameter, an independent function is established.
motivation
If a parameter has many possible values, and the values of these parameters are checked by expressions in the function, and different behaviors are made according to different parameters, the reconstruction should be used.
Benefits can be gained by "compile-time code checking" and "clearer interfaces" (if the behavior of a function is determined by the value of a parameter, then the user of the function needs not only to observe the function, but also to determine whether the parameter is "legalized". —— However, legal parameters are seldom mentioned in documents, and can only be judged by context.
Considering the benefits of compile-time validation, we also deserve to do so in order to get a clear interface.
Example
The following code establishes different subclasses under Employee according to different parameter values.
class EmployeeType { static Employee Create(int type) { switch (type) { case 0: return new Engineer(); case 1: return new Salesman(); case 2: return new Manager(); default: throw new ArgumentException("Incorrect type code value!"); } } } class Employee { } class Engineer:Employee { } class Salesman:Employee { } class Manager:Employee { }
Because this is a factory function, it cannot be implemented. Replace Conditional with Polymorphism Because the object was not created at all when the function was used. Since Employee is not expected to have too many new subclasses, it is safe to build a factory function for each subclass without worrying about a sharp increase in the number of factory functions. Firstly, a new function is established according to the parameter values.
static Employee CreateEngineer() { return new Engineer(); } static Employee CreateSalesman() { return new Salesman(); } static Employee CreateManager() { return new Manager(); }
Find the calling end of the function and put the code like the following:
Employee kent = EmployeeType.Create(0);
Replaced by:
Employee kent = EmployeeType.CreateEngineer();
When the replacement is complete, you can delete the Create() function.
Summary
If the function responds differently depending on the parameters, then it's time to refactor.
7 Preserve Whole Object
outline
You take a number of values from an object and use them as parameters in a function call, instead passing the entire object.
motivation
We often pass several data items from the same object as parameters to a function. The problem with this is that in case the called function needs new data items, it must find and modify all calls to the function. But if you pass the entire object, there's no problem.
The advantages of this technique are: (1) making the parameter column more stable; (2) improving the readability of the code.
Example
class Room { public bool WithinPlan(HeatingPlan plan) { int low = DaysTempRange().GetLow(); int high = DaysTempRange().GetHigh(); return plan.WithinRange(low, high); } public TempRange DaysTempRange() { return new TempRange(); } } class HeatingPlan { private TempRange _range; public bool WithinRange(int low, int high) { return low >= _range.GetLow() && high <= _range.GetHigh(); } } class TempRange { public int GetLow() { return 6; } public int GetHigh() { return 28; } }
In fact, there is no need to separate the information of TempRange object and pass it to WithinPlan() function.
class Room { public bool WithinPlan(HeatingPlan plan) { return plan.WithinRange(DaysTempRange()); } public TempRange DaysTempRange() { return new TempRange(); } } class HeatingPlan { private TempRange _range; public bool WithinRange(TempRange roomRange) { return roomRange.GetLow() >= _range.GetLow() && roomRange.GetHigh() <= _range.GetHigh(); } } class TempRange { public int GetLow() { return 6; } public int GetHigh() { return 28; } }
Summary
It's good to pass on the whole object, but there are always two sides to it. If a value is passed, the called function depends only on those values, not on the object to which they belong. But if the whole object is passed, the object where the called function is located needs to depend on the parameter object. If this deteriorates the dependency structure, this refactoring should not be used.
To Be Continued......